├── .travis.yml ├── AUTHORS ├── autogen.sh ├── examples ├── leak-01.c ├── leak-02.c ├── leak-03.c ├── api-01.c ├── Makefile └── segv-01.c ├── log-malloc2.pc.in ├── NEWS ├── scripts ├── log-malloc.pm.in ├── log-malloc-trackusage.pl ├── log-malloc.pl ├── log-malloc-findleak.pl └── backtrace2line.pl ├── Makefile.am ├── src ├── log-malloc2_api.c ├── log-malloc2_internal.h └── log-malloc2.c ├── ChangeLog ├── include ├── log-malloc2_util.h └── log-malloc2.h ├── config.h.in ├── configure.ac ├── COPYING-LGPL ├── README.md ├── missing ├── README ├── install-sh ├── INSTALL ├── depcomp └── COPYING /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: c 3 | before_script: ./autogen.sh 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | log-malloc2 3 | 4 | MAINTAINER: 5 | 6 | Samuel Behan <_samuel_._behan_(at)_dob_._sk> 7 | 8 | BASED ON WORK OF: 9 | 10 | Ivan Tikhonov 11 | 12 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | test -n "$srcdir" || srcdir=`dirname "$0"` 3 | test -n "$srcdir" || srcdir=. 4 | 5 | autoreconf --force --install --verbose "$srcdir" 6 | test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" 7 | -------------------------------------------------------------------------------- /examples/leak-01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | char *x = malloc(2000); 8 | 9 | x = malloc(100); 10 | 11 | free(x); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /examples/leak-02.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | char *x = malloc(2000); 9 | 10 | x = malloc(100); 11 | 12 | sleep(60); 13 | free(x); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /examples/leak-03.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void __attribute__ ((noinline)) own(char **ptr) 7 | { 8 | *ptr = malloc(100); 9 | } 10 | 11 | int main() 12 | { 13 | char *x = malloc(2000); 14 | 15 | own(&x); 16 | 17 | x = malloc(1000); 18 | 19 | free(x); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /log-malloc2.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | includedir=${prefix}/include 4 | libdir=@libdir@ 5 | libexecdir=@libexecdir@ 6 | LD_PRELOAD=${libdir}/liblog-malloc2.so 7 | 8 | Name: log-malloc2 9 | Description: Memory tracking library 10 | Version: @PACKAGE_VERSION@ 11 | Cflags: -I${includedir}/log-malloc2 12 | Libs: -L${libdir} -llog-malloc2 13 | -------------------------------------------------------------------------------- /examples/api-01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "log-malloc2.h" 6 | 7 | int main() 8 | { 9 | char *x = malloc(2000); 10 | 11 | LOG_MALLOC_SAVE(savepoint1, 0); 12 | 13 | x = malloc(100); 14 | x[0] = '\0'; 15 | 16 | LOG_MALLOC_COMPARE(savepoint1, 0); 17 | ssize_t t = LOG_MALLOC_COMPARE(savepoint1, 0); 18 | printf("TEST = %ld\n", t); 19 | LOG_MALLOC_ASSERT(savepoint1, 0); 20 | 21 | //sleep(500); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 0.3.0 2014-11-01 2 | 3 | IMPROVEMENTS 4 | 5 | * see Changelog 6 | 7 | 0.2.3 2013-09-24 8 | 9 | BUGFIX 10 | 11 | * fixed pointer formating 12 | * automake tools update 13 | 14 | 0.2.3 2012-03-29 15 | 16 | IMPROVEMENTS 17 | 18 | * improved library compatibility 19 | * detect if backtrace() is available 20 | * some docu fixes 21 | 22 | 0.2.2 2012-03-26 23 | 24 | IMPROVEMENTS 25 | 26 | * track really allocated memory using malloc_usable_size() 27 | 28 | 0.2.1 2012-02-14 29 | 30 | BUGFIX + IMPROVEMENTS 31 | 32 | * tracking more functions 33 | * fixed possible segfault if alloc fails 34 | 35 | 0.2.0 2012-02-08 36 | 37 | INITAL RELEASE 38 | 39 | * initial public release 40 | * autoconf/automake packaged 41 | * minimal documentation in README file 42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 4 examples 3 | 4 | CFLAGS2 = -Wall -rdynamic -fPIC -g -I../include 5 | 6 | ifeq ($(USE_PKGCONFIG),1) 7 | CFLAGS_API = $(shell pkg-config --cflags log-malloc2) 8 | LDLIBS_API = $(shell pkg-config --libs log-malloc2) 9 | else 10 | CWD := $(shell pwd) 11 | CFLAGS_API = -I../include 12 | LDLIBS_API = -L../.libs -llog-malloc2 -Wl,-rpath,$(realpath $(CWD)/../.libs) 13 | endif 14 | 15 | 16 | PROGRAMS = leak-01 leak-02 leak-03 api-01 segv-01 17 | 18 | # make tar 19 | .PHONY: all 20 | all: $(PROGRAMS) 21 | 22 | api-%: api-%.c 23 | $(CC) $(CFLAGS) $(CFLAGS2) $(CFLAGS_API) $(LDLIBS_API) $^ -o $@ 24 | 25 | leak-%: leak-%.c 26 | $(CC) $(CFLAGS) $(CFLAGS2) $^ -o $@ 27 | 28 | segv-%: segv-%.c 29 | $(CC) $(CFLAGS) $(CFLAGS2) $^ -o $@ 30 | 31 | clean: 32 | rm -f $(PROGRAMS) 33 | 34 | #EOF 35 | -------------------------------------------------------------------------------- /scripts/log-malloc.pm.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # log-malloc2 / config module 3 | # Config module 4 | # 5 | # Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2013-2015 6 | # 7 | # License: GNU GPLv3 (http://www.gnu.org/licenses/gpl.html) 8 | # 9 | # Web: 10 | # http://devel.dob.sk/log-malloc2 11 | # http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 12 | # https://github.com/samsk/log-malloc2 (git repo) 13 | # 14 | # 15 | package log_malloc::config; 16 | 17 | use strict; 18 | 19 | my $prefix = "@prefix@"; 20 | my $exec_prefix = "@exec_prefix@"; 21 | my $includedir = "${prefix}/include"; 22 | my $libdir = "@libdir@"; 23 | my $libexecdir = "@libexecdir@"; 24 | 25 | # 26 | # shared funcs 27 | # 28 | 29 | # LD_PRELOAD 30 | sub LD_PRELOAD() 31 | { 32 | return "$libdir/liblog-malloc2.so"; 33 | } 34 | 35 | 1; 36 | # EOF 37 | -------------------------------------------------------------------------------- /examples/segv-01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | static void sighandler(int signo) 12 | { 13 | char buf[256]; 14 | ssize_t len = 0; 15 | const char *signame = NULL; 16 | 17 | // this is not safe to use in MT apps 18 | signame = strsignal(signo); 19 | 20 | len = snprintf(buf, sizeof(buf), "\n--- SIGNAL %d (%s) RECEIVED ---\n", 21 | signo, signame); 22 | write(STDERR_FILENO, buf, len); 23 | 24 | // backtrace + maps (because of ASLR) 25 | log_malloc_backtrace(STDERR_FILENO); 26 | 27 | _exit(EXIT_FAILURE); 28 | return; 29 | } 30 | 31 | int main() 32 | { 33 | char *x = (char *)0x1; 34 | 35 | // setup signal 36 | signal(SIGSEGV, &sighandler); 37 | 38 | // raise segfault anyhow 39 | x[123] = 234; 40 | raise(SIGSEGV); 41 | 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## log-malloc2: 2 | 3 | # general 4 | AUTOMAKE_OPTIONS = subdir-objects 5 | ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} 6 | 7 | ## libtool archive target "liblog-malloc2.la". 8 | lib_LTLIBRARIES = liblog-malloc2.la 9 | 10 | ## libtool to include ABI version information in the generated shared 11 | liblog_malloc2_la_LDFLAGS = -version-info $(LOG_MALLOC2_SO_VERSION) 12 | 13 | ## source file list for the "liblog-malloc2.la" target. 14 | liblog_malloc2_la_SOURCES = src/log-malloc2.c src/log-malloc2_api.c src/log-malloc2_internal.h 15 | 16 | ## includes 17 | AM_CPPFLAGS = -I$(top_srcdir)/include 18 | pkginclude_HEADERS = include/log-malloc2.h include/log-malloc2_util.h 19 | 20 | ## scripts 21 | dist_libexec_SCRIPTS = scripts/backtrace2line.pl scripts/log-malloc.pl \ 22 | scripts/log-malloc-findleak.pl scripts/log-malloc-trackusage.pl 23 | libexec_SCRIPTS = scripts/log-malloc.pm 24 | 25 | install-exec-hook: 26 | for i in $(dist_libexec_SCRIPTS); do bn=`basename $${i}`;\ 27 | $(LN_S) -f "${libexecdir}/$${bn}" "$(bindir)/$${bn%.pl}"; done; 28 | 29 | ## pkconfig 30 | pkgconfigdir = $(libdir)/pkgconfig 31 | pkgconfig_DATA = log-malloc2.pc 32 | 33 | ## scripts dist 34 | dist_noinst_SCRIPTS = autogen.sh 35 | 36 | ## examples 37 | dist_noinst_DATA = examples/Makefile examples/*.c 38 | 39 | # manpages 40 | scripts_man_MANS = $(dist_libexec_SCRIPTS:.pl=.1) 41 | man_MANS = $(scripts_man_MANS) 42 | %.1: %.pl 43 | pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \ 44 | --section=1 $< > $@ 45 | CLEANFILES = $(man_MANS) 46 | 47 | ## test 48 | .PHONY: test 49 | -------------------------------------------------------------------------------- /src/log-malloc2_api.c: -------------------------------------------------------------------------------- 1 | /* 2 | * log-malloc2 API 3 | * Malloc logging library with backtrace and byte-exact memory tracking. 4 | * 5 | * Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2013-2015 6 | * 7 | * License: GNU LGPLv3 (http://www.gnu.org/licenses/lgpl.html) 8 | * 9 | * Web: 10 | * http://devel.dob.sk/log-malloc2 11 | * http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 12 | * https://github.com/samsk/log-malloc2 (git repo) 13 | * 14 | */ 15 | 16 | #ifdef HAVE_CONFIG_H 17 | #include "config.h" 18 | #endif 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "log-malloc2.h" 28 | #include "log-malloc2_internal.h" 29 | 30 | /* 31 | * API FUNCTIONS 32 | */ 33 | size_t log_malloc_get_usage(void) 34 | { 35 | const log_malloc_ctx_t *ctx = log_malloc_ctx_get(); 36 | 37 | return ctx->mem_used; 38 | } 39 | 40 | /* enable trace to LOG_MALLOC_TRACE_FD */ 41 | void log_malloc_trace_enable(void) 42 | { 43 | log_malloc_ctx_t *ctx = log_malloc_ctx_get(); 44 | 45 | ctx->memlog_disabled = false; 46 | return; 47 | } 48 | 49 | /* disable trace */ 50 | void log_malloc_trace_disable(void) 51 | { 52 | log_malloc_ctx_t *ctx = log_malloc_ctx_get(); 53 | 54 | ctx->memlog_disabled = true; 55 | return; 56 | } 57 | 58 | /* sprintf trace */ 59 | int log_malloc_trace_printf(const char *fmt, ...) 60 | { 61 | int s; 62 | int w = 0; 63 | char buf[1024]; 64 | va_list args; 65 | log_malloc_ctx_t *ctx = log_malloc_ctx_get(); 66 | 67 | va_start(args, fmt); 68 | s = vsnprintf(buf, sizeof(buf), fmt, args); 69 | va_end(args); 70 | 71 | { 72 | int ww = 0; 73 | const int max = ((s > (sizeof(buf) - 1)) ? (sizeof(buf) - 1) : s); 74 | 75 | buf[max - 1] = '\n'; 76 | ww = write(ctx->memlog_fd, buf, max); 77 | } 78 | return w; 79 | } 80 | 81 | /* EOF */ 82 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2 | 0.4.1 Thu May 23 16:09:22 CEST 2019 3 | - fix linking of libunwind on Ubuntu (thanks ashok3t) 4 | 5 | 0.4.0 Thu Sep 10 08:52:33 CEST 2015 6 | - libunwind backtracing performance optimized 7 | 8 | 0.4.0b Sun Aug 2 22:20:42 CEST 2015 9 | - use libunwind for backtrace if available 10 | - scripts modified to support decoding of libunwind based backtrace 11 | 12 | 0.3.0 Sun Nov 23 21:12:54 CET 2014 13 | - add manpages 14 | - release 15 | 16 | 0.3.0b2 Thu Nov 20 23:10:47 CET 2014 17 | - backtrace2line.pl support for decoding native glibc backtraces 18 | - add log-malloc2_util.h inline only helper functions 19 | 20 | 0.3.0b Mon Nov 10 00:00:00 CET 2014 21 | - code cleanup 22 | - using costructor/destructor instead of init/fini 23 | - improved protection against multiple inits 24 | - reduced exported symbols 25 | - added /proc/self/maps printing (to make addr2line mapping easier) 26 | - remove that yummy segfault in realloc that has been till now optimized away by gcc 27 | - implemented few API functions for working with library directly 28 | - added macros that make leaked memory hunting a bit easier 29 | - autodisabling trace if trace-fd not opened for writing 30 | - added backtrace2symbols translation scripts 31 | - added log-malloc trace file analysis scripts 32 | - provide pkg-config 33 | - added script for easier log-malloc trace start 34 | - clang warning fixed 35 | - etc.. 36 | 37 | 0.2.4 Wed Sep 24 22:15:31 CEST 2013 38 | - removed dummy prefix 0x from %p printouts (I'm pretty blind - I've fixed 39 | it 'lightyears' ago in some private copy and not pushed it to repo ;-) 40 | - added possibility to disable call counts, not everyone needs them and they 41 | might harm performance, because of using CAS operation 42 | 43 | 0.2.3 Thu Mar 29 18:58:35 CEST 2012 44 | - improved initialization to be compatible with libraries 45 | using malloc functions in lib constructor functions (like libproc) 46 | - detect if backtrace() and backtrace_symbols_fd() is available 47 | - some docu improvements 48 | 49 | 0.2.2 Tue Mar 26 19:22:43 CEST 2012 50 | - track real size of allocated memory using malloc_usable_size 51 | 52 | 0.2.1 Wed Feb 14 16:12:05 CET 2012 53 | - added posix_memalign/valloc tracking 54 | - operate safely if allocation fails 55 | 56 | 0.2.0 Wed Feb 8 19:42:13 CET 2012 57 | - initial public release 58 | -------------------------------------------------------------------------------- /include/log-malloc2_util.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_MALLOC2_UTIL_H 2 | #define LOG_MALLOC2_UTIL_H 3 | /* 4 | * log-malloc2_util 5 | * Helper function, all inlined, no linking required. 6 | * 7 | * Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2011-2015 8 | * 9 | * License: MIT (http://opensource.org/licenses/MIT) (free to use, modify, relicense...) 10 | * 11 | * Web: 12 | * http://devel.dob.sk/log-malloc2 13 | * http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 14 | * https://github.com/samsk/log-malloc2 (git repo) 15 | * 16 | */ 17 | 18 | #include 19 | 20 | #ifndef LOG_MALLOC_BACKTRACE_SIZE 21 | #define LOG_MALLOC_BACKTRACE_SIZE 7 22 | #endif 23 | 24 | 25 | /* API functions */ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #define LOG_MALLOC_WRITE(fd, msg) \ 32 | (void)write((fd), (msg), (sizeof((msg)) / sizeof((msg[0]))) - 1); 33 | 34 | /** pre-init backtrace 35 | * @note: backtrace() function might allocate some memory on first call, what is 36 | * a potentially dangerous operation if handling SEGV. Calling this 37 | * function in a safe situation (aplication start) will avoid this. 38 | * 39 | */ 40 | static inline void log_malloc_backtrace_init(void) 41 | { 42 | void *bt[LOG_MALLOC_BACKTRACE_SIZE]; 43 | 44 | backtrace(bt, LOG_MALLOC_BACKTRACE_SIZE); 45 | return; 46 | } 47 | 48 | /** printout complete backtrace to 49 | * @param fd output file descriptor (usually STDERR_FILENO) 50 | */ 51 | static inline ssize_t log_malloc_backtrace(int fd) 52 | { 53 | int fdin = -1; 54 | ssize_t nbt = 0; 55 | ssize_t len = 0; 56 | char buffer[BUFSIZ]; 57 | void *bt[LOG_MALLOC_BACKTRACE_SIZE]; 58 | 59 | nbt = backtrace(bt, LOG_MALLOC_BACKTRACE_SIZE); 60 | if(nbt) 61 | { 62 | LOG_MALLOC_WRITE(fd, "\n======= Backtrace =========\n"); 63 | backtrace_symbols_fd(bt, nbt, fd); 64 | 65 | fdin = open("/proc/self/maps", 0); 66 | if(fdin != -1) 67 | { 68 | LOG_MALLOC_WRITE(fd, "======= Memory map ========\n"); 69 | 70 | // ignoring EINTR here, use SA_RESTART to fix if problem 71 | while((len = read(fdin, buffer, sizeof(buffer))) > 0) 72 | write(fd, buffer, len); 73 | 74 | close(fdin); 75 | } 76 | LOG_MALLOC_WRITE(fd, "===========================\n"); 77 | } 78 | 79 | return nbt; 80 | } 81 | 82 | #undef LOG_MALLOC_WRITE 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/log-malloc2_internal.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_MALLOC2_INTERNAL_H 2 | #define LOG_MALLOC2_INTERNAL_H 3 | /* 4 | * log-malloc2 API 5 | * Malloc logging library with backtrace and byte-exact memory tracking. 6 | * 7 | * Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2013-2015 8 | * 9 | * License: GNU LGPLv3 (http://www.gnu.org/licenses/lgpl.html) 10 | * 11 | * Web: 12 | * http://devel.dob.sk/log-malloc2 13 | * http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 14 | * https://github.com/samsk/log-malloc2 (git repo) 15 | * 16 | */ 17 | 18 | #ifdef HAVE_CONFIG_H 19 | #include "config.h" 20 | #endif 21 | 22 | #include 23 | #include 24 | 25 | #ifdef HAVE_STDBOOL_H 26 | #include 27 | #else 28 | #define bool uint8_t 29 | #define false 0 30 | #define true 1 31 | #endif 32 | 33 | /* pthreads support */ 34 | #ifdef HAVE_LIBPTHREAD 35 | #include 36 | #endif 37 | 38 | /* pthread shortcuts */ 39 | #ifdef HAVE_LIBPTHREAD 40 | # define LOCK_INIT() 1 41 | # define LOCK(lock) (pthread_mutex_trylock(&(lock)) == 0) 42 | # define UNLOCK(lock) (pthread_mutex_unlock(&(lock))) 43 | #else 44 | # define LOCK_INIT() 1 45 | # define LOCK(lock) 1 46 | # define UNLOCK(lock) 0 47 | #endif 48 | 49 | 50 | /* init constants */ 51 | #define LOG_MALLOC_INIT_NULL 0xFAB321 52 | #define LOG_MALLOC_INIT_DONE 0x123FAB 53 | #define LOG_MALLOC_FINI_DONE 0xFAFBFC 54 | 55 | /* global context */ 56 | typedef struct log_malloc_ctx_s { 57 | sig_atomic_t init_done; 58 | sig_atomic_t mem_used; 59 | sig_atomic_t mem_rused; 60 | struct { 61 | sig_atomic_t malloc; 62 | sig_atomic_t calloc; 63 | sig_atomic_t realloc; 64 | sig_atomic_t memalign; 65 | sig_atomic_t posix_memalign; 66 | sig_atomic_t valloc; 67 | sig_atomic_t free; 68 | sig_atomic_t unrel_sum; /* unrealiable call count sum */ 69 | } stat; 70 | int memlog_fd; 71 | int statm_fd; 72 | bool memlog_disabled; 73 | clock_t clock_start; 74 | #ifdef HAVE_LIBPTHREAD 75 | pthread_mutex_t loglock; 76 | #endif 77 | } log_malloc_ctx_t; 78 | 79 | #define LOG_MALLOC_CTX_INIT_BASE \ 80 | LOG_MALLOC_INIT_NULL, \ 81 | 0, \ 82 | 0, \ 83 | {0, 0, 0, 0, 0, 0, 0, 0}, \ 84 | LOG_MALLOC_TRACE_FD, \ 85 | -1, \ 86 | false, \ 87 | 0 88 | 89 | #ifdef HAVE_LIBPTHREAD 90 | #define LOG_MALLOC_CTX_INIT \ 91 | { \ 92 | LOG_MALLOC_CTX_INIT_BASE, \ 93 | PTHREAD_MUTEX_INITIALIZER, \ 94 | } 95 | #else 96 | #define LOG_MALLOC_CTX_INIT \ 97 | { \ 98 | LOG_MALLOC_CTX_INIT_BASE, \ 99 | } 100 | #endif 101 | 102 | /* API function */ 103 | log_malloc_ctx_t *log_malloc_ctx_get(void); 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Disable functions call counting */ 4 | #undef DISABLE_CALL_COUNTS 5 | 6 | /* Define to 1 if you have the `backtrace' function. */ 7 | #undef HAVE_BACKTRACE 8 | 9 | /* Define to 1 if you have the `backtrace_symbols_fd' function. */ 10 | #undef HAVE_BACKTRACE_SYMBOLS_FD 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_DLFCN_H 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_FCNTL_H 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_INTTYPES_H 20 | 21 | /* Define to 1 if you have the `dl' library (-ldl). */ 22 | #undef HAVE_LIBDL 23 | 24 | /* Define to 1 if you have the `pthread' library (-lpthread). */ 25 | #undef HAVE_LIBPTHREAD 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_LIBUNWIND_H 29 | 30 | /* Define to 1 if you have the `malloc_usable_size' function. */ 31 | #undef HAVE_MALLOC_USABLE_SIZE 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_MEMORY_H 35 | 36 | /* Define to 1 if you have the `pread' function. */ 37 | #undef HAVE_PREAD 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_STDBOOL_H 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #undef HAVE_STDINT_H 44 | 45 | /* Define to 1 if you have the header file. */ 46 | #undef HAVE_STDLIB_H 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #undef HAVE_STRINGS_H 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #undef HAVE_STRING_H 53 | 54 | /* Define to 1 if you have the header file. */ 55 | #undef HAVE_SYS_STAT_H 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #undef HAVE_SYS_TIME_H 59 | 60 | /* Define to 1 if you have the header file. */ 61 | #undef HAVE_SYS_TYPES_H 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #undef HAVE_UNISTD_H 65 | 66 | /* Use libunwind for backtrace */ 67 | #undef HAVE_UNWIND 68 | 69 | /* Generate detailed libunwind backtrace */ 70 | #undef HAVE_UNWIND_DETAIL 71 | 72 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 73 | #undef LT_OBJDIR 74 | 75 | /* Define to the address where bug reports for this package should be sent. */ 76 | #undef PACKAGE_BUGREPORT 77 | 78 | /* Define to the full name of this package. */ 79 | #undef PACKAGE_NAME 80 | 81 | /* Define to the full name and version of this package. */ 82 | #undef PACKAGE_STRING 83 | 84 | /* Define to the one symbol short name of this package. */ 85 | #undef PACKAGE_TARNAME 86 | 87 | /* Define to the home page for this package. */ 88 | #undef PACKAGE_URL 89 | 90 | /* Define to the version of this package. */ 91 | #undef PACKAGE_VERSION 92 | 93 | /* Define to 1 if you have the ANSI C header files. */ 94 | #undef STDC_HEADERS 95 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | ## liblog-malloc2 2 | #### 3 | 4 | AC_INIT([log-malloc2], [0.4.1], [_samuel_._behan_(at)_dob_._sk], [log-malloc2], 5 | [http://devel.dob.sk/log-malloc2]) 6 | AC_PREREQ([2.59]) 7 | AM_INIT_AUTOMAKE([1.10 -Wall no-define]) 8 | 9 | # Generate two configuration headers; one for building the library itself with 10 | # an autogenerated template, and a second one that will be installed alongside 11 | # the library. 12 | AC_CONFIG_HEADERS([config.h]) 13 | 14 | # Checks for programs. 15 | AC_PROG_CXX 16 | AC_PROG_AWK 17 | AC_PROG_CC 18 | AC_PROG_CPP 19 | AC_PROG_INSTALL 20 | AC_PROG_LN_S 21 | AC_PROG_MAKE_SET 22 | AC_PROG_RANLIB 23 | 24 | LT_INIT([disable-static]) 25 | 26 | AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h sys/time.h unistd.h stdbool.h libunwind.h]) 27 | 28 | AC_CHECK_FUNCS([ pread backtrace backtrace_symbols_fd ]) 29 | 30 | AC_CHECK_LIB(dl, dlsym, , [ 31 | AC_MSG_ERROR([ 32 | Can't find the dl library (libdl.so) !])]) 33 | 34 | AC_CHECK_LIB(pthread, pthread_mutex_trylock, , [ 35 | AC_MSG_ERROR([ 36 | Can't find the pthread library (libpthread.so) !])]) 37 | 38 | no_libunwind=no 39 | AC_ARG_WITH([libunwind], 40 | AS_HELP_STRING([--without-libunwind], [do not use libunwind for backtrace]), 41 | [no_libunwind=yes], [no_libunwind=no] 42 | ) 43 | 44 | libunwind_detail=no 45 | AC_ARG_WITH([libunwind-detail], 46 | AS_HELP_STRING([--with-libunwind-detail], [more details in libunwind backtrace]), 47 | [libunwind_detail=yes], [libunwind_detail=no] 48 | ) 49 | 50 | libunwind=no 51 | if test "x$no_libunwind" != "xyes"; then 52 | AC_CHECK_HEADER([libunwind.h], [libunwind=yes], [libunwind=no]) 53 | 54 | if test "x$libunwind_detail" = "xyes"; then 55 | AC_DEFINE(HAVE_UNWIND_DETAIL, 1, [Generate detailed libunwind backtrace]) 56 | fi 57 | fi 58 | 59 | no_optimize=no 60 | AC_ARG_ENABLE([optimize], 61 | AS_HELP_STRING([--disable-optimize], [do not optimize library]), 62 | [no_optimize=yes], [no_optimize=no] 63 | ) 64 | 65 | no_call_count=no 66 | AC_ARG_ENABLE([call-count], 67 | AS_HELP_STRING([--disable-call-count], [do not count function calls]), 68 | [no_call_count=yes], [no_call_count=no] 69 | ) 70 | 71 | if test "x$no_call_count" = "xyes"; then 72 | AC_DEFINE(DISABLE_CALL_COUNTS, 1, [Disable functions call counting]) 73 | fi 74 | 75 | no_usable_size=no 76 | AC_ARG_ENABLE([usable-size], 77 | AS_HELP_STRING([--disable-usable-size], [do not check usable size]), 78 | [no_usable_size=no], [no_usable_size=yes] 79 | ) 80 | 81 | if test "x$no_usable_size" = "xyes"; then 82 | AC_CHECK_FUNCS([ malloc_usable_size ]) 83 | fi 84 | 85 | # FLAGS 86 | CFLAGS="-DWITH_PTHREADS -D_GNU_SOURCE -Xcompiler -nostartfiles" 87 | LDFLAGS="-ldl -lpthread" 88 | 89 | if test "x$no_optimize" != "xyes" 90 | then 91 | CFLAGS="$CFLAGS -O2" 92 | else 93 | CFLAGS="$CFLAGS -g" 94 | fi 95 | 96 | if test "x$libunwind" != "xno" 97 | then 98 | LDFLAGS="$LDFLAGS -lunwind-generic -lunwind" 99 | AC_DEFINE(HAVE_UNWIND, 1, [Use libunwind for backtrace]) 100 | fi 101 | 102 | # Define these substitions here to keep all version information in one place. 103 | # For information on how to properly maintain the library version information, 104 | # refer to the libtool manual, section "Updating library version information": 105 | # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 106 | AC_SUBST([LOG_MALLOC2_SO_VERSION], [1:0:0]) 107 | AC_SUBST([LOG_MALLOC2_API_VERSION], [0.4]) 108 | 109 | # Override the template file name of the generated .pc file, so that there 110 | # is no need to rename the template file when the API version changes. 111 | AC_CONFIG_FILES([Makefile]) 112 | AC_CONFIG_FILES([log-malloc2.pc]) 113 | AC_CONFIG_FILES([scripts/log-malloc.pm]) 114 | AC_OUTPUT 115 | 116 | # config results 117 | echo 118 | echo "HAVE_UNWIND $libunwind" 119 | echo "HAVE_UNWIND_DETAIL $libunwind_detail" 120 | echo 121 | 122 | -------------------------------------------------------------------------------- /include/log-malloc2.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_MALLOC2_H 2 | #define LOG_MALLOC2_H 3 | /* 4 | * log-malloc2 5 | * Malloc logging library with backtrace and byte-exact memory tracking. 6 | * 7 | * Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2011-2015 8 | * 9 | * License: GNU LGPLv3 (http://www.gnu.org/licenses/lgpl.html) 10 | * 11 | * Web: 12 | * http://devel.dob.sk/log-malloc2 13 | * http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 14 | * https://github.com/samsk/log-malloc2 (git repo) 15 | * 16 | */ 17 | 18 | #include 19 | 20 | /* config (LINUX specific) */ 21 | #ifndef LOG_MALLOC_TRACE_FD 22 | #define LOG_MALLOC_TRACE_FD 1022 23 | #endif 24 | 25 | #ifndef LOG_MALLOC_BACKTRACE_COUNT 26 | #define LOG_MALLOC_BACKTRACE_COUNT 7 27 | #endif 28 | 29 | #ifndef LOG_MALLOC_STATM_PATH 30 | #define LOG_MALLOC_STATM_PATH "/proc/self/statm" 31 | #endif 32 | 33 | #ifndef LOG_MALLOC_MAPS_PATH 34 | #define LOG_MALLOC_MAPS_PATH "/proc/self/maps" 35 | #endif 36 | 37 | /* API macros */ 38 | 39 | /* disable macros */ 40 | #ifndef LOG_MALLOC_NDEBUG 41 | 42 | /** crate savepoint storing actual memory usage */ 43 | #define LOG_MALLOC_SAVE(name, trace) \ 44 | size_t _log_malloc_sp_##name = log_malloc_get_usage(); \ 45 | ssize_t _log_malloc_sp_diff_##name = 0; \ 46 | static ssize_t _log_malloc_sp_iter_##name = -1; \ 47 | _log_malloc_sp_iter_##name++; \ 48 | if((trace)) \ 49 | log_malloc_trace_printf("# SP %s(%s:%u)/%s: saved=%lu\n", \ 50 | __FUNCTION__, __FILE__, __LINE__, #name, \ 51 | _log_malloc_sp_##name); 52 | 53 | /** update given savepoint with actual memory usage */ 54 | #define LOG_MALLOC_UPDATE(name, trace) \ 55 | _log_malloc_sp_##name = log_malloc_get_usage(); \ 56 | if((trace)) \ 57 | log_malloc_trace_printf("# SP %s(%s:%u)/%s: updated=%lu\n", \ 58 | __FUNCTION__, __FILE__, __LINE__, #name, \ 59 | _log_malloc_sp_##name); 60 | 61 | 62 | /** test memory level for change */ 63 | #define LOG_MALLOC_COMPARE(name, trace) \ 64 | ( \ 65 | _log_malloc_sp_diff_##name = \ 66 | (log_malloc_get_usage() - _log_malloc_sp_##name), \ 67 | (((_log_malloc_sp_diff_##name != 0) || (trace)) ? \ 68 | log_malloc_trace_printf("# SP-COMPARE %s(%s:%u)/%s: expected=%lu, diff=%+ld\n",\ 69 | __FUNCTION__, __FILE__, __LINE__, #name, \ 70 | _log_malloc_sp_##name, _log_malloc_sp_diff_##name) : 0) \ 71 | , _log_malloc_sp_diff_##name ) 72 | 73 | #ifndef NDEBUG 74 | /** assert if memory usage differs 75 | * @note Using internal __asert_fail function ! 76 | */ 77 | #define LOG_MALLOC_ASSERT(name, iter) \ 78 | if(((iter) == 0) || ((iter)) == _log_malloc_sp_iter_##name) \ 79 | { \ 80 | size_t _log_malloc_sp_now_##name = log_malloc_get_usage(); \ 81 | if(!(_log_malloc_sp_##name == _log_malloc_sp_now_##name)) \ 82 | __assert_fail(#name "-mem-usage-before != " #name "-mem-usage-after", \ 83 | __FILE__, __LINE__, __FUNCTION__); \ 84 | } 85 | #else 86 | #define LOG_MALLOC_ASSERT(name, iter) 87 | #endif 88 | 89 | #else 90 | 91 | /* noops (NOTE: use of NULL here is experimental :) */ 92 | #define LOG_MALLOC_SAVE(name, trace) 93 | #define LOG_MALLOC_UPDATE(name, trace) 94 | #define LOG_MALLOC_COMPARE(name, trace) NULL 95 | #define LOG_MALLOC_ASSERT(name, trace) 96 | 97 | #endif 98 | 99 | /* API functions */ 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | /** get current memory usage */ 106 | size_t log_malloc_get_usage(void); 107 | 108 | /** enable trace to LOG_MALLOC_TRACE_FD */ 109 | void log_malloc_trace_enable(void); 110 | 111 | /** disable trace */ 112 | void log_malloc_trace_disable(void); 113 | 114 | /** trace smth. to LOG_MALLOC_TRACE_FD */ 115 | int log_malloc_trace_printf(const char *fmt, ...) 116 | __attribute__((format(printf, 1, 2))); 117 | 118 | #ifdef __cplusplus 119 | } 120 | #endif 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /scripts/log-malloc-trackusage.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # log-malloc2 / trackusage 3 | # Outputs memory usage 4 | # 5 | # Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2013-2015 6 | # 7 | # License: GNU GPLv3 (http://www.gnu.org/licenses/gpl.html) 8 | # 9 | # Web: 10 | # http://devel.dob.sk/log-malloc2 11 | # http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 12 | # https://github.com/samsk/log-malloc2 (git repo) 13 | # 14 | # 15 | package log_malloc::trackusage; 16 | 17 | use strict; 18 | use Getopt::Long; 19 | use Pod::Usage; 20 | use Data::Dumper; 21 | 22 | # VERSION 23 | our $VERSION = "0.4"; 24 | 25 | # EXEC 26 | sub main(@); 27 | exit(main(@ARGV)) if(!caller()); 28 | 29 | # 30 | # PUBLIC FUNCTIONS 31 | # 32 | 33 | # process(\@lines, @use_real_usage): @usage 34 | sub process(\@;$) 35 | { 36 | my ($lines, $rusage) = @_; 37 | my ($min, $max, $rmin, $rmax) = (0, 0, 0, 0); 38 | 39 | PROCESS: 40 | my @result; 41 | my $init = 0; 42 | for(my $ii = 0; $ii <= $#$lines; $ii++) 43 | { 44 | $init = 1, next 45 | if($init != 2 && $$lines[$ii] =~ /^\+ (INIT|FINI)/o); 46 | next 47 | if(!$init); 48 | 49 | # matching [MEM-STATUS:MEM-STATUS-USABLE] in 50 | # + FUNCTION MEM-CHANGE MEM-IN? MEM-OUT? (FUNCTION-PARAMS) [MEM-STATUS:MEM-STATUS-USABLE] 51 | if($$lines[$ii] =~ /^\+.*?\[(\d+):(\d*)\]/o) 52 | { 53 | my ($use, $ruse) = ($1, $2); 54 | my $val = $use; 55 | 56 | $val = $ruse 57 | if($rusage && defined($ruse) && $ruse ne ''); 58 | push(@result, $val); 59 | } 60 | } 61 | 62 | # this was only a snippet of log-malloc trace file 63 | if(!$init) 64 | { 65 | $init = 2; 66 | goto PROCESS; 67 | } 68 | return @result; 69 | } 70 | 71 | # 72 | # MAIN 73 | # 74 | 75 | sub main(@) 76 | { 77 | my (@argv) = @_; 78 | my ($file, $usable_size, $verbose, $man, $help); 79 | 80 | @ARGV = @argv; 81 | GetOptions( 82 | "<>" => sub { $file = $_[0] . ''; }, 83 | "usable-size" => \$usable_size, 84 | "h|?|help" => \$help, 85 | "man" => \$man, 86 | ) || pod2usage( -verbose => 0, -exitval => 1 ); 87 | @argv = @ARGV; 88 | 89 | pod2usage( -verbose => 1 ) 90 | if($help); 91 | pod2usage( -verbose => 3 ) 92 | if($man); 93 | 94 | pod2usage( -msg => "$0: log-malloc trace filename required", 95 | -verbose => 0, -exitval => 1 ) 96 | if(!$file); 97 | 98 | # whole file to memory 99 | my $fd; 100 | die("$0: failed to open file '$file' - $!\n") 101 | if(!open($fd, $file)); 102 | 103 | my (@lines) = <$fd>; 104 | close($fd); 105 | 106 | # process data 107 | my (@result) = process(@lines, $usable_size); 108 | 109 | # print out 110 | foreach my $elem (@result) 111 | { 112 | print $elem . "\n"; 113 | } 114 | 115 | return 0; 116 | } 117 | 118 | 1; 119 | 120 | =pod 121 | 122 | =head1 NAME 123 | 124 | log-malloc-trackusage - track allocated memory usage 125 | 126 | =head1 SYNOPSIS 127 | 128 | log-malloc-trackusage [ OPTIONS ] I 129 | 130 | =head1 DESCRIPTION 131 | 132 | This script analyzes input trace file and prints out how memory usage changed by every 133 | memory allocation/release. 134 | 135 | NOTE: This script can be also used as perl module. 136 | 137 | =head1 ARGUMENTS 138 | 139 | =over 4 140 | 141 | =item I 142 | 143 | Path to file containing log-malloc2 trace (can be only part of it). 144 | 145 | =back 146 | 147 | =head1 OPTIONS 148 | 149 | =over 4 150 | 151 | =item B<--usable-size> 152 | 153 | Prints really allocated/assigned memory instead of how much memory has been requested. 154 | 155 | =item B<-h> 156 | 157 | =item B<--help> 158 | 159 | Print help. 160 | 161 | =item B<--man> 162 | 163 | Show man page. 164 | 165 | =back 166 | 167 | =head1 EXAMPLES 168 | 169 | $ log-malloc-trackusage /tmp/lm.trace 170 | 3736 171 | 3836 172 | 3736 173 | 174 | =head1 LICENSE 175 | 176 | This script is released under GNU GPLv3 License. 177 | See L. 178 | 179 | =head1 AUTHOR 180 | 181 | Samuel Behan - L, L 182 | 183 | =head1 SEE ALSO 184 | 185 | L 186 | 187 | =cut 188 | 189 | #EOF 190 | -------------------------------------------------------------------------------- /scripts/log-malloc.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # log-malloc2 3 | # Execute command with log-malloc tracer enabled 4 | # 5 | # Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2013-2015 6 | # 7 | # License: GNU GPLv3 (http://www.gnu.org/licenses/gpl.html) 8 | # 9 | # Web: 10 | # http://devel.dob.sk/log-malloc2 11 | # http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 12 | # https://github.com/samsk/log-malloc2 (git repo) 13 | # 14 | # 15 | package log_malloc; 16 | 17 | use strict; 18 | use Cwd; 19 | use POSIX qw(dup2); 20 | use Getopt::Long; 21 | use Pod::Usage; 22 | use Data::Dumper; 23 | use File::Basename; 24 | 25 | # VERSION 26 | our $VERSION = "0.4"; 27 | 28 | my $LIBEXECDIR; 29 | BEGIN { $LIBEXECDIR = Cwd::abs_path(dirname(readlink(__FILE__) || __FILE__)); }; 30 | 31 | # include submodule (optional) 32 | use lib $LIBEXECDIR; 33 | my $LOGMALLOC_HAVE_PM = 0; 34 | $LOGMALLOC_HAVE_PM = 1 35 | if(eval { require "log-malloc.pm"; }); 36 | 37 | # EXEC 38 | sub main(@); 39 | exit(main(@ARGV)) if(!caller()); 40 | 41 | # 42 | # INTERNAL FUNCTIONS 43 | # 44 | 45 | sub rotateFile($) 46 | { 47 | my ($file) = @_; 48 | 49 | for(my $ii = 1; $ii <= 200; $ii++) 50 | { 51 | my $fn = $file . "." . $ii; 52 | 53 | next 54 | if(-e $fn); 55 | rename($file, $fn); 56 | return 1; 57 | } 58 | return 0; 59 | } 60 | 61 | # 62 | # MAIN 63 | # 64 | 65 | sub main(@) 66 | { 67 | my (@argv) = @_; 68 | my ($logfile, $rotate, $verbose, $man, $help); 69 | 70 | # cmdline parsing 71 | @ARGV = @argv; 72 | eval { 73 | # XXX: using last is hacky way to stop getopt processing if non-option encourted 74 | # => Inadvisably Applied Perl 75 | no warnings 'exiting'; 76 | GetOptions( 77 | "o|output=s" => \$logfile, 78 | "oo|ro|rotate-output=s" => sub { $logfile = $_[1]; $rotate = 1; }, 79 | "v|verbose" => \$verbose, 80 | "<>" => sub { unshift(@ARGV, "$_[0]"); last; }, 81 | "h|?|help" => \$help, 82 | "man" => \$man, 83 | ) || pod2usage( -verbose => 0, -exitval => 1 ); 84 | }; 85 | @argv = @ARGV; 86 | 87 | pod2usage( -verbose => 1 ) 88 | if($help); 89 | pod2usage( -verbose => 3 ) 90 | if($man); 91 | 92 | pod2usage( -msg => "$0: command to execute is required !", 93 | -verbose => 0, -exitval => 1 ) 94 | if(!@ARGV); 95 | 96 | # find LD_PRELOAD library path 97 | my $LD_PRELOAD; 98 | # - preferr use of local library (if not installed) 99 | if($LIBEXECDIR && -d "$LIBEXECDIR/../.libs" 100 | && -e "$LIBEXECDIR/../.libs/liblog-malloc2.so") 101 | { 102 | $LD_PRELOAD = "$LIBEXECDIR/../.libs/liblog-malloc2.so"; 103 | } 104 | # - get config from log-malloc.pm 105 | elsif($LOGMALLOC_HAVE_PM) 106 | { 107 | $LD_PRELOAD = log_malloc::config::LD_PRELOAD(); 108 | } 109 | # - get config from pkg-config 110 | else 111 | { 112 | $LD_PRELOAD = `pkg-config log-malloc2 --variable=LD_PRELOAD`; 113 | die("$0: failed to locate log-malloc2 library via pkg-config !\n") 114 | if($? != 0 || !$LD_PRELOAD); 115 | } 116 | 117 | # open trace file 118 | if($logfile) 119 | { 120 | rotateFile($logfile) 121 | if($rotate); 122 | unlink($logfile); 123 | 124 | my $fd; 125 | if($logfile ne "-") 126 | { 127 | die("$0: failed to open trace file '$logfile' - $!\n") 128 | if(!open($fd, ">", $logfile)); 129 | } 130 | else 131 | { 132 | $fd = \*STDERR; 133 | } 134 | 135 | # logfile -> 1022 136 | die("$0: failed to dup2() trace fileno - $!\n") 137 | if(dup2(fileno($fd), 1022) < 0); 138 | 139 | close($fd); 140 | } 141 | 142 | # setup env 143 | $ENV{'LD_PRELOAD'} = $LD_PRELOAD; 144 | warn "LD_PRELOAD = $LD_PRELOAD\n" 145 | if($verbose); 146 | 147 | no warnings 'exec'; 148 | warn("$0: failed to execute '@argv' - $!\n") 149 | if(!exec({ $argv[0] } @argv)); 150 | 151 | unlink($logfile); 152 | return 1; 153 | } 154 | 155 | 1; 156 | 157 | =pod 158 | 159 | =head1 NAME 160 | 161 | log-malloc - start given command traced with log-malloc2 library 162 | 163 | =head1 SYNOPSIS 164 | 165 | log-malloc-trackusage [ OPTIONS ] I ... 166 | 167 | =head1 DESCRIPTION 168 | 169 | This script start given command with log-malloc2 library preloaded, thus 170 | enabling memory allocations tracing. By default all traces are written 171 | to filedescriptor 1022, but can be redirected B<--output> to file. 172 | 173 | liblog-malloc2.so selection: 174 | - if starting from compilation directory, .libs/liblog-malloc2.so 175 | - library path from log-malloc.pm 176 | - library path found via pkg-config 177 | 178 | =head1 ARGUMENTS 179 | 180 | =over 4 181 | 182 | =item I 183 | 184 | Command with arguments that should be executed and traced. 185 | 186 | =back 187 | 188 | =head1 OPTIONS 189 | 190 | =over 4 191 | 192 | =item B<-o> I 193 | 194 | =item B<--output> I 195 | 196 | Redirect log-malloc2 trace to given I. If '-' specified as B than trace will be redirected to 197 | STDERR. 198 | 199 | =item B<-oo> I 200 | 201 | =item B<-ro> I 202 | 203 | =item B<--rotate-output> I 204 | 205 | The same as B<--output> but I will be automatically rotated instead of being overwritten - FILE.1, FILE.2... 206 | 207 | =item B<-v> 208 | 209 | =item B<--verbose> 210 | 211 | Enable verbose messages. 212 | 213 | =item B<-h> 214 | 215 | =item B<--help> 216 | 217 | Print help. 218 | 219 | =item B<--man> 220 | 221 | Show man page. 222 | 223 | =back 224 | 225 | =head1 EXAMPLES 226 | 227 | $ log-malloc -o /tmp/lm.trace ./examples/leak-01 228 | 229 | *** log-malloc trace-fd = 1022 *** 230 | 231 | 232 | =head1 LICENSE 233 | 234 | This script is released under GNU GPLv3 License. 235 | See L. 236 | 237 | =head1 AUTHOR 238 | 239 | Samuel Behan - L, L 240 | 241 | =head1 SEE ALSO 242 | 243 | L, L 244 | 245 | =cut 246 | 247 | #EOF 248 | -------------------------------------------------------------------------------- /COPYING-LGPL: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | log-malloc2 2 | =========== 3 | 4 | *log-malloc2* is **pre-loadable** library tracking all memory allocations of a program. It 5 | produces simple text trace output, that makes it easy to find leaks and also identify their origin. 6 | 7 | [![Build Status](https://travis-ci.org/samsk/log-malloc2.svg)](https://travis-ci.org/samsk/log-malloc2) 8 | 9 | 10 | # Features 11 | 12 | - logging to file descriptor 1022 (if opened) 13 | - call stack **backtrace** (via GNU backtrace() or libunwind) 14 | - **requested memory tracking** (byte-exact) 15 | - allocated memory tracking (byte-exact - using malloc_usable_size()) 16 | - process memory status tracking (from /proc/self/statm) 17 | - call counting 18 | - thread safe 19 | - optional **C API** for runtime memory usage checking 20 | 21 | 22 | # Usage 23 | 24 | `log-malloc -o /tmp/program.log command args` 25 | 26 | OR 27 | 28 | `LD_PRELOAD=./liblog-malloc2.so command args ... 1022>/tmp/program.log` 29 | 30 | # Performance 31 | 32 | There is (non-)small performance penalty related to writing to logfile. One can improve this by redirecting write to tmpfs or similar fast-write filesystem. If log-malloc2 is compiled **without libunwind**, additionally a synchronization mutex is used while writing to logfile, thus every memory allocation is acting as giant synchronization lock (slowed down by write to logfile). 33 | 34 | 35 | # Helper scripts 36 | 37 | - `backtrace2line` 38 | - Script to automatically convert backtrace in files and line numbers. 39 | - Can also deal with [ASLR](https://en.wikipedia.org/wiki/Address_space_layout_randomization) randomized addresses. 40 | 41 | - `log-malloc-findleak` 42 | - Script to discover possible program memory leaks from trace file 43 | 44 | - `log-malloc-trackusage` 45 | - Script to track program memory usage over time. 46 | 47 | 48 | # C API 49 | 50 | - ```size_t log_malloc_get_usage(void)``` 51 | - Get actual program memory usage in bytes 52 | 53 | - ```void log_malloc_trace_enable(void)``` 54 | - Enable trace messages to be printed to trace fd. 55 | 56 | - ```void log_malloc_trace_disable(void)``` 57 | - Disable trace messages. 58 | 59 | - ```int log_malloc_trace_printf(const char *fmt, ...)``` 60 | - Printf smth. to trace fd (message size is limited to 1024 bytes). 61 | 62 | - ```LOG_MALLOC_SAVE(name, trace)``` [MACRO] 63 | - Creates savepoint with given _name_ that stores actual memory usage. 64 | - If _trace_ is true, message will be logged to trace fd. 65 | 66 | - ```LOG_MALLOC_UPDATE(name, trace)``` [MACRO] 67 | - Updates actual memory usage in savepoint with given _name_. 68 | - If _trace_ is true, trace message will be logged to trace fd. 69 | 70 | - ```LOG_MALLOC_COMPARE(name, trace)``` [MACRO] 71 | - Compares actual memory usage with the saved one under given _name_. 72 | - If _trace_ is true, trace message will be logged to trace fd. 73 | - Call returns memory usage difference (size_t). 74 | 75 | - ```LOG_MALLOC_ASSERT(name, iter)``` [MACRO] 76 | - ASSERT with fail, if actual memory usage differs from the one saved in savepoint. 77 | - _iter_ can specify that assertion should be checked first after given number of LOG_MALLOC_SAVE() iterations. 78 | 79 | - ```LOG_MALLOC_NDEBUG``` [MACRO] 80 | - If defined, above macros will generate no code. 81 | 82 | 83 | # C INLINE API 84 | 85 | - ```void log_malloc_backtrace_init(void)``` 86 | - Pre-initializes backtrace() function, to avoid later memory alocations. Use of this function is optional. 87 | 88 | - ```ssize_t log_malloc_backtrace(int fd)``` 89 | - Generate current backtrace including process memory map (/proc/self/maps) to make backtrace symbol conversion easier. 90 | - Generated output can be directly pasted to _backtrace2line_ script. 91 | 92 | 93 | # Author 94 | 95 | - ***Samuel Behan*** 96 | - **contact**: samuel(dot)behan(at)dob(dot)sk 97 | - **homepage**: [http://dob.sk](http://dob.sk?u=github) 98 | - **projects**: [http://devel.dob.sk](http://devel.dob.sk?u=github) 99 | 100 | 101 | # Licensing 102 | 103 | * [LGPLv3](https://www.gnu.org/licenses/lgpl.html) for C code (library) 104 | * [GPLv3](https://www.gnu.org/licenses/gpl.html) for Perl code (scripts) 105 | 106 | 107 | # See Also 108 | 109 | * More/Detailed info in project [README](README) 110 | * Project home: [http://devel.dob.sk/log-malloc2](http://devel.dob.sk/log-malloc2?u=github) 111 | 112 | 113 | # Examples 114 | 115 | ###Example Trace Output 116 | 117 | $ log-malloc -o - ./examples/leak-01 118 | 119 | *** log-malloc trace-fd = 1022 *** 120 | 121 | + malloc 53 0x7f9bff564080 [85:160]! 122 | + calloc 1182 0x7f9bff5640e0 [1267:1384] (1182 1)! 123 | + malloc 53 0x7f9bff5645b0 [1320:1472]! 124 | + malloc 56 0x7f9bff564610 [1376:1560]! 125 | + calloc 360 0x7f9bff564670 [1736:1952] (15 24)! 126 | + calloc 32 0x7f9bff564030 [32:72] (1 32) #3183 168 131 1 0 84 0 127 | /lib64/libdl.so.2(+0x1960)[0x7f9bfcfa8960] 128 | /lib64/libdl.so.2(dlsym+0x5a)[0x7f9bfcfa843a] 129 | /home/sam/devel/log-malloc2/scripts/../.libs/liblog-malloc2.so(+0x12e3)[0x7f9bfd7882e3] 130 | /lib64/ld-linux-x86-64.so.2(+0xfa0b)[0x7f9bfd99ba0b] 131 | /lib64/ld-linux-x86-64.so.2(+0xfb1c)[0x7f9bfd99bb1c] 132 | /lib64/ld-linux-x86-64.so.2(+0x140a)[0x7f9bfd98d40a] 133 | /lib64/libdl.so.2(+0x13a0)[0x7f9bfcfa83a0] 134 | # PID 23451 135 | # EXE /home/sam/devel/log-malloc2/examples/leak-01 136 | # CWD /home/sam/devel/log-malloc2 137 | + INIT [1736:1952] malloc=3 calloc=3 realloc=0 memalign=0/0 valloc=0 free=0 138 | + malloc 2000 0x7f9bff564800 [3736:3992] #3183 168 131 1 0 84 0 139 | ./examples/leak-01(main+0x32)[0x7f9bfdbb1af2] 140 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f9bfd3f01cb] 141 | ./examples/leak-01(+0x9a9)[0x7f9bfdbb19a9] 142 | [0x0] 143 | + malloc 100 0x7f9bff565000 [3836:4128] #3183 168 131 1 0 84 0 144 | ./examples/leak-01(main+0x40)[0x7f9bfdbb1b00] 145 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f9bfd3f01cb] 146 | ./examples/leak-01(+0x9a9)[0x7f9bfdbb19a9] 147 | [0x0] 148 | + free -100 0x7f9bff565000 [3736:3992] #3183 168 131 1 0 84 0 149 | + FINI [3736:3992] malloc=5 calloc=3 realloc=0 memalign=0/0 valloc=0 free=1 150 | # FILE /proc/self/maps 151 | 7f9bfcd90000-7f9bfcda6000 r-xp 00000000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 152 | 7f9bfcda6000-7f9bfcfa5000 ---p 00016000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 153 | 7f9bfcfa5000-7f9bfcfa6000 r--p 00015000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 154 | 7f9bfcfa6000-7f9bfcfa7000 rw-p 00016000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 155 | 7f9bfcfa7000-7f9bfcfaa000 r-xp 00000000 fe:02 819448 /lib64/libdl-2.19.so 156 | 7f9bfcfaa000-7f9bfd1a9000 ---p 00003000 fe:02 819448 /lib64/libdl-2.19.so 157 | 7f9bfd1a9000-7f9bfd1aa000 r--p 00002000 fe:02 819448 /lib64/libdl-2.19.so 158 | 7f9bfd1aa000-7f9bfd1ab000 rw-p 00003000 fe:02 819448 /lib64/libdl-2.19.so 159 | 7f9bfd1ab000-7f9bfd1c5000 r-xp 00000000 fe:02 818913 /lib64/libpthread-2.19.so 160 | 7f9bfd1c5000-7f9bfd3c5000 ---p 0001a000 fe:02 818913 /lib64/libpthread-2.19.so 161 | 7f9bfd3c5000-7f9bfd3c6000 r--p 0001a000 fe:02 818913 /lib64/libpthread-2.19.so 162 | 7f9bfd3c6000-7f9bfd3c7000 rw-p 0001b000 fe:02 818913 /lib64/libpthread-2.19.so 163 | 7f9bfd3c7000-7f9bfd3cb000 rw-p 00000000 00:00 0 164 | 7f9bfd3cb000-7f9bfd57d000 r-xp 00000000 fe:02 819451 /lib64/libc-2.19.so 165 | 7f9bfd57d000-7f9bfd77d000 ---p 001b2000 fe:02 819451 /lib64/libc-2.19.so 166 | 7f9bfd77d000-7f9bfd781000 r--p 001b2000 fe:02 819451 /lib64/libc-2.19.so 167 | 7f9bfd781000-7f9bfd783000 rw-p 001b6000 fe:02 819451 /lib64/libc-2.19.so 168 | 7f9bfd783000-7f9bfd787000 rw-p 00000000 00:00 0 169 | 7f9bfd787000-7f9bfd78b000 r-xp 00000000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 170 | 7f9bfd78b000-7f9bfd98a000 ---p 00004000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 171 | 7f9bfd98a000-7f9bfd98b000 r--p 00003000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 172 | 7f9bfd98b000-7f9bfd98c000 rw-p 00004000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 173 | 7f9bfd98c000-7f9bfd9ae000 r-xp 00000000 fe:02 818908 /lib64/ld-2.19.so 174 | 7f9bfdb99000-7f9bfdb9d000 rw-p 00000000 00:00 0 175 | 7f9bfdbad000-7f9bfdbae000 rw-p 00000000 00:00 0 176 | 7f9bfdbae000-7f9bfdbaf000 r--p 00022000 fe:02 818908 /lib64/ld-2.19.so 177 | 7f9bfdbaf000-7f9bfdbb0000 rw-p 00023000 fe:02 818908 /lib64/ld-2.19.so 178 | 7f9bfdbb0000-7f9bfdbb1000 rw-p 00000000 00:00 0 179 | 7f9bfdbb1000-7f9bfdbb2000 r-xp 00000000 fe:02 15340 /home/sam/devel/log-malloc2/examples/leak-01 180 | 7f9bfddb1000-7f9bfddb2000 r--p 00000000 fe:02 15340 /home/sam/devel/log-malloc2/examples/leak-01 181 | 7f9bfddb2000-7f9bfddb3000 rw-p 00001000 fe:02 15340 /home/sam/devel/log-malloc2/examples/leak-01 182 | 7f9bff564000-7f9bff585000 rw-p 00000000 00:00 0 [heap] 183 | 7fffb5471000-7fffb5493000 rw-p 00000000 00:00 0 [stack] 184 | 7fffb54cf000-7fffb54d1000 r-xp 00000000 00:00 0 [vdso] 185 | ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 186 | 187 | ###Example leak 188 | 189 | $ ./scripts/log-malloc-findleak.pl /tmp/lm2.trace 190 | SUSPECTED 1 LEAKS: 191 | 0x7f4688a04000 leaked 100 bytes (0.10 KiB) allocated by malloc (line: 1) 192 | FUNCTION FILE SYMBOL 193 | main examples/leak-01.c:10 ./examples/leak-01(main+0x40)[0x7f4687a6fb50] 194 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f46872ae1cb] 195 | _start ??:? ./examples/leak-01(+0x9f9)[0x7f4687a6f9f9] 196 | [0x0] 197 | 198 | 199 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | 4 | scriptversion=2012-01-06.13; # UTC 5 | 6 | # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 7 | # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. 8 | # Originally by Fran,cois Pinard , 1996. 9 | 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | if test $# -eq 0; then 29 | echo 1>&2 "Try \`$0 --help' for more information" 30 | exit 1 31 | fi 32 | 33 | run=: 34 | sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' 35 | sed_minuso='s/.* -o \([^ ]*\).*/\1/p' 36 | 37 | # In the cases where this matters, `missing' is being run in the 38 | # srcdir already. 39 | if test -f configure.ac; then 40 | configure_ac=configure.ac 41 | else 42 | configure_ac=configure.in 43 | fi 44 | 45 | msg="missing on your system" 46 | 47 | case $1 in 48 | --run) 49 | # Try to run requested program, and just exit if it succeeds. 50 | run= 51 | shift 52 | "$@" && exit 0 53 | # Exit code 63 means version mismatch. This often happens 54 | # when the user try to use an ancient version of a tool on 55 | # a file that requires a minimum version. In this case we 56 | # we should proceed has if the program had been absent, or 57 | # if --run hadn't been passed. 58 | if test $? = 63; then 59 | run=: 60 | msg="probably too old" 61 | fi 62 | ;; 63 | 64 | -h|--h|--he|--hel|--help) 65 | echo "\ 66 | $0 [OPTION]... PROGRAM [ARGUMENT]... 67 | 68 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 69 | error status if there is no known handling for PROGRAM. 70 | 71 | Options: 72 | -h, --help display this help and exit 73 | -v, --version output version information and exit 74 | --run try to run the given command, and emulate it if it fails 75 | 76 | Supported PROGRAM values: 77 | aclocal touch file \`aclocal.m4' 78 | autoconf touch file \`configure' 79 | autoheader touch file \`config.h.in' 80 | autom4te touch the output file, or create a stub one 81 | automake touch all \`Makefile.in' files 82 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 83 | flex create \`lex.yy.c', if possible, from existing .c 84 | help2man touch the output file 85 | lex create \`lex.yy.c', if possible, from existing .c 86 | makeinfo touch the output file 87 | yacc create \`y.tab.[ch]', if possible, from existing .[ch] 88 | 89 | Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and 90 | \`g' are ignored when checking the name. 91 | 92 | Send bug reports to ." 93 | exit $? 94 | ;; 95 | 96 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 97 | echo "missing $scriptversion (GNU Automake)" 98 | exit $? 99 | ;; 100 | 101 | -*) 102 | echo 1>&2 "$0: Unknown \`$1' option" 103 | echo 1>&2 "Try \`$0 --help' for more information" 104 | exit 1 105 | ;; 106 | 107 | esac 108 | 109 | # normalize program name to check for. 110 | program=`echo "$1" | sed ' 111 | s/^gnu-//; t 112 | s/^gnu//; t 113 | s/^g//; t'` 114 | 115 | # Now exit if we have it, but it failed. Also exit now if we 116 | # don't have it and --version was passed (most likely to detect 117 | # the program). This is about non-GNU programs, so use $1 not 118 | # $program. 119 | case $1 in 120 | lex*|yacc*) 121 | # Not GNU programs, they don't have --version. 122 | ;; 123 | 124 | *) 125 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 126 | # We have it, but it failed. 127 | exit 1 128 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 129 | # Could not run --version or --help. This is probably someone 130 | # running `$TOOL --version' or `$TOOL --help' to check whether 131 | # $TOOL exists and not knowing $TOOL uses missing. 132 | exit 1 133 | fi 134 | ;; 135 | esac 136 | 137 | # If it does not exist, or fails to run (possibly an outdated version), 138 | # try to emulate it. 139 | case $program in 140 | aclocal*) 141 | echo 1>&2 "\ 142 | WARNING: \`$1' is $msg. You should only need it if 143 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 144 | to install the \`Automake' and \`Perl' packages. Grab them from 145 | any GNU archive site." 146 | touch aclocal.m4 147 | ;; 148 | 149 | autoconf*) 150 | echo 1>&2 "\ 151 | WARNING: \`$1' is $msg. You should only need it if 152 | you modified \`${configure_ac}'. You might want to install the 153 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 154 | archive site." 155 | touch configure 156 | ;; 157 | 158 | autoheader*) 159 | echo 1>&2 "\ 160 | WARNING: \`$1' is $msg. You should only need it if 161 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 162 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 163 | from any GNU archive site." 164 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 165 | test -z "$files" && files="config.h" 166 | touch_files= 167 | for f in $files; do 168 | case $f in 169 | *:*) touch_files="$touch_files "`echo "$f" | 170 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 171 | *) touch_files="$touch_files $f.in";; 172 | esac 173 | done 174 | touch $touch_files 175 | ;; 176 | 177 | automake*) 178 | echo 1>&2 "\ 179 | WARNING: \`$1' is $msg. You should only need it if 180 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 181 | You might want to install the \`Automake' and \`Perl' packages. 182 | Grab them from any GNU archive site." 183 | find . -type f -name Makefile.am -print | 184 | sed 's/\.am$/.in/' | 185 | while read f; do touch "$f"; done 186 | ;; 187 | 188 | autom4te*) 189 | echo 1>&2 "\ 190 | WARNING: \`$1' is needed, but is $msg. 191 | You might have modified some files without having the 192 | proper tools for further handling them. 193 | You can get \`$1' as part of \`Autoconf' from any GNU 194 | archive site." 195 | 196 | file=`echo "$*" | sed -n "$sed_output"` 197 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 198 | if test -f "$file"; then 199 | touch $file 200 | else 201 | test -z "$file" || exec >$file 202 | echo "#! /bin/sh" 203 | echo "# Created by GNU Automake missing as a replacement of" 204 | echo "# $ $@" 205 | echo "exit 0" 206 | chmod +x $file 207 | exit 1 208 | fi 209 | ;; 210 | 211 | bison*|yacc*) 212 | echo 1>&2 "\ 213 | WARNING: \`$1' $msg. You should only need it if 214 | you modified a \`.y' file. You may need the \`Bison' package 215 | in order for those modifications to take effect. You can get 216 | \`Bison' from any GNU archive site." 217 | rm -f y.tab.c y.tab.h 218 | if test $# -ne 1; then 219 | eval LASTARG=\${$#} 220 | case $LASTARG in 221 | *.y) 222 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 223 | if test -f "$SRCFILE"; then 224 | cp "$SRCFILE" y.tab.c 225 | fi 226 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 227 | if test -f "$SRCFILE"; then 228 | cp "$SRCFILE" y.tab.h 229 | fi 230 | ;; 231 | esac 232 | fi 233 | if test ! -f y.tab.h; then 234 | echo >y.tab.h 235 | fi 236 | if test ! -f y.tab.c; then 237 | echo 'main() { return 0; }' >y.tab.c 238 | fi 239 | ;; 240 | 241 | lex*|flex*) 242 | echo 1>&2 "\ 243 | WARNING: \`$1' is $msg. You should only need it if 244 | you modified a \`.l' file. You may need the \`Flex' package 245 | in order for those modifications to take effect. You can get 246 | \`Flex' from any GNU archive site." 247 | rm -f lex.yy.c 248 | if test $# -ne 1; then 249 | eval LASTARG=\${$#} 250 | case $LASTARG in 251 | *.l) 252 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 253 | if test -f "$SRCFILE"; then 254 | cp "$SRCFILE" lex.yy.c 255 | fi 256 | ;; 257 | esac 258 | fi 259 | if test ! -f lex.yy.c; then 260 | echo 'main() { return 0; }' >lex.yy.c 261 | fi 262 | ;; 263 | 264 | help2man*) 265 | echo 1>&2 "\ 266 | WARNING: \`$1' is $msg. You should only need it if 267 | you modified a dependency of a manual page. You may need the 268 | \`Help2man' package in order for those modifications to take 269 | effect. You can get \`Help2man' from any GNU archive site." 270 | 271 | file=`echo "$*" | sed -n "$sed_output"` 272 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 273 | if test -f "$file"; then 274 | touch $file 275 | else 276 | test -z "$file" || exec >$file 277 | echo ".ab help2man is required to generate this page" 278 | exit $? 279 | fi 280 | ;; 281 | 282 | makeinfo*) 283 | echo 1>&2 "\ 284 | WARNING: \`$1' is $msg. You should only need it if 285 | you modified a \`.texi' or \`.texinfo' file, or any other file 286 | indirectly affecting the aspect of the manual. The spurious 287 | call might also be the consequence of using a buggy \`make' (AIX, 288 | DU, IRIX). You might want to install the \`Texinfo' package or 289 | the \`GNU make' package. Grab either from any GNU archive site." 290 | # The file to touch is that specified with -o ... 291 | file=`echo "$*" | sed -n "$sed_output"` 292 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 293 | if test -z "$file"; then 294 | # ... or it is the one specified with @setfilename ... 295 | infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 296 | file=`sed -n ' 297 | /^@setfilename/{ 298 | s/.* \([^ ]*\) *$/\1/ 299 | p 300 | q 301 | }' $infile` 302 | # ... or it is derived from the source name (dir/f.texi becomes f.info) 303 | test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info 304 | fi 305 | # If the file does not exist, the user really needs makeinfo; 306 | # let's fail without touching anything. 307 | test -f $file || exit 1 308 | touch $file 309 | ;; 310 | 311 | *) 312 | echo 1>&2 "\ 313 | WARNING: \`$1' is needed, and is $msg. 314 | You might have modified some files without having the 315 | proper tools for further handling them. Check the \`README' file, 316 | it often tells you about the needed prerequisites for installing 317 | this package. You may also peek at any GNU archive site, in case 318 | some other package would contain this missing \`$1' program." 319 | exit 1 320 | ;; 321 | esac 322 | 323 | exit 0 324 | 325 | # Local variables: 326 | # eval: (add-hook 'write-file-hooks 'time-stamp) 327 | # time-stamp-start: "scriptversion=" 328 | # time-stamp-format: "%:y-%02m-%02d.%02H" 329 | # time-stamp-time-zone: "UTC" 330 | # time-stamp-end: "; # UTC" 331 | # End: 332 | -------------------------------------------------------------------------------- /scripts/log-malloc-findleak.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # log-malloc2 / findleak 3 | # Find memory leaks in log-malloc trace file 4 | # 5 | # Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2013-2015 6 | # 7 | # License: GNU GPLv3 (http://www.gnu.org/licenses/gpl.html) 8 | # 9 | # Web: 10 | # http://devel.dob.sk/log-malloc2 11 | # http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 12 | # https://github.com/samsk/log-malloc2 (git repo) 13 | # 14 | # 15 | package log_malloc::findleak; 16 | 17 | use strict; 18 | use Cwd; 19 | use Getopt::Long; 20 | use Pod::Usage; 21 | use Data::Dumper; 22 | use File::Basename; 23 | 24 | # VERSION 25 | our $VERSION = "0.4"; 26 | 27 | my $LIBEXECDIR; 28 | BEGIN { $LIBEXECDIR = Cwd::abs_path(dirname(readlink(__FILE__) || __FILE__)); }; 29 | 30 | # include submodule (optional) 31 | use lib $LIBEXECDIR; 32 | my $LOGMALLOC_HAVE_BT = 0; 33 | $LOGMALLOC_HAVE_BT = 1 34 | if(eval { require "backtrace2line.pl" }); 35 | 36 | # EXEC 37 | sub main(@); 38 | exit(main(@ARGV)) if(!caller()); 39 | 40 | # 41 | # PUBLIC FUNCTIONS 42 | # 43 | 44 | # parse(\@lines): (\%address_map, \%address_data, \%other_data) 45 | sub parse(\@) 46 | { 47 | my ($lines) = @_; 48 | 49 | my $init = 0; 50 | my (%map, %data, %other, $payload); 51 | for(my $ii = 0; $ii <= $#$lines; $ii++) 52 | { 53 | $init = 1, $payload = undef, ($2 ? %map = %data = () : undef), next 54 | if($$lines[$ii] =~ /^\+ ((INIT)|FINI)/o); 55 | 56 | if($$lines[$ii] =~ /^\+ /o) 57 | { 58 | # splitting 59 | # + FUNCTION MEM-CHANGE MEM-IN? MEM-OUT? (FUNCTION-PARAMS) [MEM-STATUS:MEM-STATUS-USABLE] 60 | my (undef, $func, $size, $addr1, $addr2) = split(/ /o, $$lines[$ii]); 61 | 62 | my $key = $addr1; 63 | if($func eq 'realloc' && $addr1 ne $addr2) 64 | { 65 | $map{ $addr2 } = $map{ $addr1 }; 66 | delete($map{ $addr1 }); 67 | $key = $addr2; 68 | } 69 | 70 | $map{ $key } += $size; 71 | $payload = []; 72 | push(@{$data{ $key }}, { 73 | call => $func, 74 | line => $ii + 1, 75 | change => $size, 76 | backtrace => $payload}); 77 | } 78 | elsif($$lines[$ii] =~ /# (\w+) (.+?)$/o) 79 | { 80 | my ($key, $value) = ($1, $2); 81 | 82 | # check if payload there 83 | if($$lines[$ii + 1] =~ /^\W /o) 84 | { 85 | $other{$key} = $value; 86 | } 87 | else 88 | { 89 | $payload = []; 90 | ${$other{$key}}{$value} = $payload; 91 | } 92 | } 93 | # other operation, stop payloading 94 | elsif($$lines[$ii] =~ /^\W /o) 95 | { 96 | $payload = undef; 97 | } 98 | elsif($payload) 99 | { 100 | chomp($$lines[$ii]); 101 | 102 | push(@$payload, $$lines[$ii]); 103 | } 104 | } 105 | return (\%map, \%data, \%other) 106 | } 107 | 108 | # process($pid, \@lines, %params): \%leaks 109 | sub process($\@%) 110 | { 111 | my ($pid, $lines, %params) = @_; 112 | 113 | my ($map, $data, $other) = parse(@$lines); 114 | 115 | # filter non-freed mem allocs 116 | my %leaks; 117 | foreach my $key (keys(%$map)) 118 | { 119 | next 120 | if(!($map->{$key})); 121 | 122 | $leaks{$key} = $data->{$key}; 123 | } 124 | 125 | # translate 126 | if($params{'translate'}) 127 | { 128 | warn("WARN: backtrace2line.pl not found, can not translate !\n") 129 | if(!$LOGMALLOC_HAVE_BT); 130 | 131 | my ($cwd, $maps); 132 | $pid = $other->{'PID'} 133 | if($other && $other->{'PID'}); 134 | $cwd = $other->{'CWD'} 135 | if($other && $other->{'CWD'}); 136 | $maps = $other->{'FILE'}->{'/proc/self/maps'} 137 | if($other && $other->{'FILE'} && $other->{'FILE'}->{'/proc/self/maps'}); 138 | 139 | foreach my $key (keys(%leaks)) 140 | { 141 | foreach my $rec (@{$leaks{$key}}) 142 | { 143 | my $bt = $rec->{'backtrace'}; 144 | 145 | my @lines = log_malloc::backtrace2line::process($maps, $cwd, $pid, @$bt); 146 | 147 | if(@lines) 148 | { 149 | $rec->{'backtrace-ori'} = $rec->{'backtrace'}; 150 | $rec->{'backtrace'} = \@lines; 151 | } 152 | } 153 | } 154 | } 155 | 156 | return \%leaks; 157 | } 158 | 159 | sub main(@) 160 | { 161 | my (@argv) = @_; 162 | my ($file, $verbose, $pid, $fullName, $man, $help); 163 | my $no_translate=0; 164 | 165 | @ARGV = @argv; 166 | GetOptions( 167 | "<>" => sub { $file = $_[0] . ''; }, 168 | "p|pid=i" => \$pid, 169 | "no-translate" => \$no_translate, 170 | "full-names" => \$fullName, 171 | "h|?|help" => \$help, 172 | "man" => \$man, 173 | ) || pod2usage( -verbose => 0, -exitval => 1 ); 174 | @argv = @ARGV; 175 | 176 | pod2usage( -verbose => 1 ) 177 | if($help); 178 | pod2usage( -verbose => 3 ) 179 | if($man); 180 | 181 | pod2usage( -msg => "$0: log-malloc trace filename required", 182 | -verbose => 0, -exitval => 1 ) 183 | if(!$file); 184 | 185 | # whole file to memory 186 | my $fd; 187 | die("$0: failed to open file '$file' - $!\n") 188 | if(!open($fd, $file)); 189 | 190 | my (@lines) = <$fd>; 191 | close($fd); 192 | 193 | # process data 194 | my $result = process($pid, @lines, translate => !$no_translate); 195 | 196 | # color output 197 | my ($c_BOLD, $c_RST) = ("\033\[1m", "\033\[0m"); 198 | ($c_BOLD, $c_RST) = ('', '') 199 | if(!-t STDOUT); 200 | 201 | # printout 202 | if(keys(%$result)) 203 | { 204 | printf("${c_BOLD}SUSPECTED %d LEAKS:${c_RST}\n", scalar keys(%$result)); 205 | } 206 | else 207 | { 208 | print "NO LEAKS FOUND (HURRAY!)\n"; 209 | } 210 | 211 | # iterate results 212 | foreach my $key (sort { ${$result->{$a}}[0]->{line} <=> ${$result->{$b}}[0]->{line} } keys(%$result)) 213 | { 214 | # TODO: we care only about first allocation here !! 215 | my $rec = ${$result->{$key}}[0]; 216 | 217 | printf(" ${c_BOLD}%-10s leaked %d bytes (%0.2f KiB) allocated by %s (line: %d)${c_RST}\n", 218 | $key, $rec->{change}, $rec->{change} / 1024, 219 | $rec->{call}, $rec->{line}); 220 | 221 | # translated bactrace 222 | if(exists($rec->{'backtrace'})) 223 | { 224 | # get length for pretty-print 225 | my ($function_len, $filepos_len, $translated) = (20, 25); 226 | foreach my $line (@{$rec->{'backtrace'}}) 227 | { 228 | next 229 | if(!ref($line)); 230 | 231 | $function_len = length($line->{function}) 232 | if(length($line->{function}) > $function_len); 233 | 234 | # shorten filename 235 | $line->{fileFull} = $line->{file}; 236 | if(!$fullName) 237 | { 238 | my $dir = basename(dirname($line->{file})); 239 | 240 | $line->{file} = basename($line->{file}); 241 | $line->{file} = $dir . "/" . $line->{file} 242 | if($dir && $dir ne '.'); 243 | } 244 | 245 | $line->{filepos} = sprintf("%s:%s", $line->{file}, $line->{line}); 246 | $filepos_len = length($line->{filepos}) 247 | if(length($line->{filepos}) > $filepos_len); 248 | 249 | $translated = 1; 250 | } 251 | 252 | goto SYMBOLS_ONLY 253 | if(!$translated); 254 | 255 | my $fmt = sprintf("\t%%-%ds %%-%ds %%s\n", 256 | $function_len, $filepos_len); 257 | 258 | printf($fmt, "FUNCTION", "FILE", "SYMBOL") 259 | if($function_len || $filepos_len); 260 | 261 | # pretty print 262 | foreach my $line (@{$rec->{'backtrace'}}) 263 | { 264 | if(ref($line)) 265 | { 266 | printf($fmt, 267 | $line->{function}, $line->{filepos}, 268 | $line->{sym}); 269 | } 270 | else 271 | { 272 | printf($fmt, '', '', 273 | $line); 274 | } 275 | } 276 | } 277 | # only symbols 278 | else 279 | { 280 | SYMBOLS_ONLY: 281 | foreach my $line (@{$rec->{'backtrace'}}) 282 | { 283 | printf("\t%s\n", $line); 284 | } 285 | } 286 | } 287 | 288 | return 0; 289 | } 290 | 291 | 1; 292 | 293 | =pod 294 | 295 | =head1 NAME 296 | 297 | log-malloc-findleak - find suspected memory leaks in log-malloc2 trace file 298 | 299 | =head1 SYNOPSIS 300 | 301 | log-malloc-findleak [ OPTIONS ] I 302 | 303 | =head1 DESCRIPTION 304 | 305 | This script analyzes input trace file (or part of it) produced by log-malloc2 library, and prints out 306 | suspected memory leaks along with translated backtrace path to code allocating that memory. 307 | 308 | NOTE: This script can be also used as perl module. 309 | 310 | =head1 ARGUMENTS 311 | 312 | =over 4 313 | 314 | =item I 315 | 316 | Path to file containing log-malloc2 trace (can be only part of it). 317 | 318 | =back 319 | 320 | =head1 OPTIONS 321 | 322 | =over 4 323 | 324 | =item B<-p> I 325 | 326 | =item B<--pid> I 327 | 328 | Pid of a B running process, that generated given trace. This is primarily needed for backtrace 329 | to work if ASLR is enabled. 330 | 331 | =item B<--full-names> 332 | 333 | Will force full filenames with path to be shown in backtrace and not only filenames with parent directory. 334 | 335 | =item B<--no-translate> 336 | 337 | Will not translate backtrace, but print only backtrace symbols as they are in trace file. 338 | 339 | =item B<-h> 340 | 341 | =item B<--help> 342 | 343 | Print help. 344 | 345 | =item B<--man> 346 | 347 | Show man page. 348 | 349 | =back 350 | 351 | =head1 EXAMPLES 352 | 353 | # full trace file (MEMORY MAP included) 354 | $ log-malloc-findleak /tmp/lm.trace 355 | SUSPECTED 1 LEAKS: 356 | 0x7f00af5ac800 leaked 2000 bytes (1.95 KiB) allocated by malloc (line: 18) 357 | FUNCTION FILE SYMBOL 358 | main examples/leak-01.c:7 ./leak-01(main+0x32)[0x7f00ad7a4af2] 359 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f00acfe31cb] 360 | _start ??:? ./leak-01(+0x9a9)[0x7f00ad7a49a9] 361 | [0x0] 362 | 363 | # full trace file, but leak-01 has been stripped 364 | SUSPECTED 1 LEAKS: 365 | 0x7f00af5ac800 leaked 2000 bytes (1.95 KiB) allocated by malloc (line: 18) 366 | ./leak-01(main+0x32)[0x7f00ad7a4af2] 367 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f00acfe31cb] 368 | ./leak-01(+0x9a9)[0x7f00ad7a49a9] 369 | [0x0] 370 | 371 | $ log-malloc-findleak /tmp/lm.trace --no-translate 372 | SUSPECTED 1 LEAKS: 373 | 0x7f00af5ac800 leaked 2000 bytes (1.95 KiB) allocated by malloc (line: 18) 374 | ./leak-01(main+0x32)[0x7f00ad7a4af2] 375 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f00acfe31cb] 376 | ./leak-01(+0x9a9)[0x7f00ad7a49a9] 377 | [0x0] 378 | 379 | # incomplete trace file, leak-02 still running but PID is in trace file 380 | $ log-malloc-findleak /tmp/lm2.trace 381 | SUSPECTED 2 LEAKS: 382 | 0x7fe0c69fc800 leaked 2000 bytes (1.95 KiB) allocated by malloc (line: 18) 383 | FUNCTION FILE SYMBOL 384 | main examples/leak-02.c:8 ./examples/leak-02(main+0x32)[0x7fe0c59e1b42] 385 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7fe0c52201cb] 386 | _start ??:? ./examples/leak-02(+0x9f9)[0x7fe0c59e19f9] 387 | [0x0] 388 | 0x7fe0c69fd000 leaked 100 bytes (0.10 KiB) allocated by malloc (line: 23) 389 | FUNCTION FILE SYMBOL 390 | main examples/leak-02.c:10 ./examples/leak-02(main+0x40)[0x7fe0c59e1b50] 391 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7fe0c52201cb] 392 | _start ??:? ./examples/leak-02(+0x9f9)[0x7fe0c59e19f9] 393 | [0x0] 394 | 395 | # excerpt of trace file, leak-02 still running and no PID in trace file 396 | $ log-malloc-findleak /tmp/lm2.trace-part --pid 21134 397 | SUSPECTED 1 LEAKS: 398 | 0x7f4688a04000 leaked 100 bytes (0.10 KiB) allocated by malloc (line: 1) 399 | FUNCTION FILE SYMBOL 400 | main examples/leak-02.c:10 ./examples/leak-02(main+0x40)[0x7f4687a6fb50] 401 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f46872ae1cb] 402 | _start ??:? ./examples/leak-02(+0x9f9)[0x7f4687a6f9f9] 403 | [0x0] 404 | 405 | =head1 LICENSE 406 | 407 | This script is released under GNU GPLv3 License. 408 | See L. 409 | 410 | =head1 AUTHOR 411 | 412 | Samuel Behan - L, L 413 | 414 | =head1 SEE ALSO 415 | 416 | L 417 | 418 | =cut 419 | 420 | # EOF 421 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | #! /usr/bin/less 2 | ################################################################################ 3 | 4 | Program : log-malloc2 (library) 5 | Version : 0.4.1 6 | Purpose : Malloc logging library with backtrace and byte-exact memory 7 | tracking. 8 | License : GNU GPL v3 (see file COPYING) 9 | GNU LGPL v3 (see file COPYING-LGPL) 10 | Author : Samuel Behan <_samuel_._behan_(at)_dob_._sk> (c) 2011-2015 11 | Web : http://devel.dob.sk/log-malloc2 12 | http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorial) 13 | 14 | ################################################################################ 15 | 16 | --------- 17 | - ABOUT - 18 | --------- 19 | 20 | log-malloc2 is library for tracking memory functions calls, that can be 21 | preloaded using LD_PRELOAD or even directly linked to your program. 22 | 23 | It also provides simple api to programaticaly check current memory usage 24 | (bytes requested) intended for testing purposes. 25 | 26 | --- 27 | This library is partialy based on log-malloc library, hence the name 28 | log-malloc2 - and I'm too lazy to figure out better name. I've taken some 29 | ideas from this library, but it's completely rewriten to make backtracing 30 | work also on 64bit system, and to provide also additional usefull informations 31 | regarding allocated memory. 32 | 33 | 34 | ------------ 35 | - FEATURES - 36 | ------------ 37 | 38 | * logging to file descriptor 1022 (if opened) 39 | * call stack backtrace (via GNU backtrace() or libunwind) 40 | * requested memory tracking (byte-exact) 41 | * allocated memory tracking (byte-exact - using malloc_usable_size()) 42 | * process memory status tracking (from /proc/self/statm) 43 | * call counting 44 | * thread safe (used also to prevent log mixing) 45 | * optional C API for runtime memory usage checking 46 | 47 | 48 | --------- 49 | - USAGE - 50 | --------- 51 | 52 | log-malloc -o /tmp/program.log command args 53 | 54 | OR 55 | 56 | LD_PRELOAD=./liblog-malloc2.so command args ... 1022>/tmp/program.log 57 | 58 | This generates log-malloc trace file, tracking all memory operations and 59 | associated stack backtraces that helps to identify source file/line that 60 | made that memory operation. 61 | 62 | Having program compiled with debug information and -rdynamic makes backtrace 63 | call stack better readable. Aferwards, you can use backtrace2line script or 64 | addr2line tool from GNU binutils to convert backtrace addresses into exact 65 | source code line numbers (if using addr2line you have to deal with ASLR 66 | yourselves). 67 | 68 | If trace file descriptor is not opened for writing on library initialisation, 69 | trace output is automatically disabled, and should not further harm program 70 | performance anyhow. 71 | 72 | This package provides also additional scripts, that will help you to deal 73 | with log-malloc2 trace: 74 | 75 | * backtrace2line 76 | Script to automatically convert backtrace in files and line numbers. 77 | Can also deal with ASLR randomized addresses. 78 | 79 | * log-malloc-findleak 80 | Script to discover possible program memory leaks from trace file 81 | 82 | * log-malloc-trackusage 83 | Script to track program memory usage over time. 84 | 85 | These scripts can be also used as perl packages, because they export functions 86 | to parse and analyse trace file or convert backtraces (modulino concept). 87 | 88 | 89 | --------- 90 | - C API - 91 | --------- 92 | 93 | log-malloc2.h provides simple C API functions (ideal for testing) that can be used 94 | if it is directly linked to a program at compile/link time. 95 | Warning: Such a usage is not recommended in production environment! Memory tracking 96 | and call counting use memory bariers, that may degrade application performance. 97 | 98 | size_t log_malloc_get_usage(void) 99 | 100 | Get actual program memory usage in bytes 101 | 102 | void log_malloc_trace_enable(void) 103 | 104 | Enable trace messages to be printed to trace fd. 105 | 106 | void log_malloc_trace_disable(void) 107 | 108 | Disable trace messages. 109 | 110 | int log_malloc_trace_printf(const char *fmt, ...) 111 | 112 | Printf smth. to trace fd (message size is limited to 1024 bytes). 113 | 114 | LOG_MALLOC_SAVE(name, trace) [MACRO] 115 | 116 | Creates savepoint with given _name_ that stores actual memory usage. 117 | If _trace_ is true, message will be logged to trace fd. 118 | 119 | LOG_MALLOC_UPDATE(name, trace) [MACRO] 120 | 121 | Updates actual memory usage in savepoint with given _name_. 122 | If _trace_ is true, trace message will be logged to trace fd. 123 | 124 | LOG_MALLOC_COMPARE(name, trace) [MACRO] 125 | 126 | Compares actual memory usage with the saved one under given _name_. 127 | If _trace_ is true, trace message will be logged to trace fd. 128 | Call returns memory usage difference (size_t). 129 | 130 | LOG_MALLOC_ASSERT(name, iter) [MACRO] 131 | 132 | ASSERT with fail, if actual memory usage differs from the one saved in savepoint. 133 | _iter_ can specify that assertion should be checked first after 134 | given number of LOG_MALLOC_SAVE() iterations. 135 | 136 | LOG_MALLOC_NDEBUG [MACRO] 137 | 138 | If defined, above macros will generate no code. 139 | 140 | 141 | ---------------- 142 | - C INLINE API - 143 | ---------------- 144 | 145 | log-malloc2_util.h provides for convenience, few fully inlined functions, that 146 | can be used without linking library itself. 147 | 148 | void log_malloc_backtrace_init(void) 149 | 150 | Pre-initializes backtrace() function, to avoid later memory alocations. 151 | Use of this function is optional. 152 | 153 | ssize_t log_malloc_backtrace(int fd) 154 | 155 | Generate current backtrace including process memory map (/proc/self/maps) to 156 | make backtrace symbol conversion easier. Generated output can be directly 157 | pasted to backtrace2line script. 158 | 159 | 160 | -------------------- 161 | - PERFORMANCE TIPS - 162 | -------------------- 163 | 164 | * Ensure that libunwind is enabled 165 | 166 | Libunwind generates backtrace approx. 2x faster than GNU backtrace(). 167 | With libunwind there is only single write() used for logging (compared to at 168 | least 2 calls when using backtrace()). Futhermore, there is no protective mutex 169 | locking needed, what should reduce waits in multi-threaded programs. 170 | 171 | * Log to tmpfs, or other FS that handles write operation effectively 172 | 173 | If traced application intensively allocates memory, consider logging to tmpfs 174 | because writting to trace fd is the slowest operation, that might be in addition 175 | protected by a mutex (if GNU backtrace is used), thus serializing multithreaded 176 | memory allocations. 177 | 178 | 179 | --------------------------------- 180 | - TRACKED FUNCTIONS & INTERNALS - 181 | --------------------------------- 182 | 183 | * malloc 184 | * realloc 185 | * calloc 186 | Note: library changes passed parameters from calloc(nmemb, size) 187 | to calloc(1, nmemb*size). Allocated memory is exactly the same 188 | but there might(?) appear some problem due to this change. 189 | * memalign 190 | * posix_memalign 191 | * valloc 192 | * free 193 | Note: call to free are not backtraced, also free(NULL) calls are 194 | completely ignored. 195 | 196 | Library allocates additional 32 bytes (due to structure alignment) per every allocated 197 | memory. This is necessary to make byte-exact memory tracking possible. 198 | This memory is placed in front of allocated memory and stores size of allocated 199 | memory (1 x size_t) and check bits (1 x size_t) for allocated size number and 200 | real-aligned allocated memory size (1 x size_t). 201 | These data are also used to distinguish memory allocated by this library, 202 | and memory that has been allocated by something else (whatever it was, you can 203 | identify it by appended '!f' when free()-ing). 204 | 205 | This functionality makes log-malloc2 library less resistant against random 206 | memory overwrites, that will destroy library internal data (especially by 207 | realloc/free), but incorrect memory overwrites are anyway bad, and this 208 | makes them only better recognizable. 209 | 210 | Library uses malloc_usable_size() function (if available) to determine how much memory 211 | has been really allocated by libc. Allocated memory differs from requested memory, 212 | because alocated memory blocks are usualy aligend to some power of 2. 213 | 214 | Note: Allocated memory status (MEM-STATUS) might and will differ from 215 | numbers you will see in top/ps or statm data, because memory is allocated 216 | in blocks that are usually greater than requested memory, but it might 217 | be relatively close to MEM-STATUS-ALIGNED. 218 | DuckDuckGo it ;) 219 | 220 | 221 | ---------- 222 | - OUTPUT - 223 | ---------- 224 | 225 | Logfile has following structure 226 | 227 | + FUNCTION MEM-CHANGE MEM-IN? MEM-OUT? (FUNCTION-PARAMS) [MEM-STATUS:MEM-STATUS-USABLE] #STATM-DATA 228 | BACKTRACE 229 | ... 230 | ... 231 | + FUNCTION.... 232 | ... 233 | # ADDITIONAL-DATA 234 | ... 235 | 236 | Legend: 237 | 238 | FUNCTION - called function name (malloc/realloc/free...) 239 | MEM-CHANGE - bytes allocated/deallocated 240 | MEM-IN - (optional) input memory pointer 241 | MEM-OUT - (optional) (re)allocated memory pointer 242 | MEM-STATUS - actually allocated memory using functions 243 | MEM-STATUS-USABLE - sum of allocated memory reported by malloc_usable_size 244 | FUNCTION-PARAMS - parameter that has been passed to function 245 | STATM-DATA - copy of /proc/self/statm content 246 | ADDITIONAL-DATA - additional runtime data, like PID, CWD, MAPS content 247 | 248 | 249 | ------------------ 250 | - EXAMPLE OUTPUT - 251 | ------------------ 252 | 253 | $ log-malloc.pl -o - ./examples/leak-01 254 | 255 | *** log-malloc trace-fd = 1022 *** 256 | 257 | + malloc 53 0x7f9bff564080 [85:160]! 258 | + calloc 1182 0x7f9bff5640e0 [1267:1384] (1182 1)! 259 | + malloc 53 0x7f9bff5645b0 [1320:1472]! 260 | + malloc 56 0x7f9bff564610 [1376:1560]! 261 | + calloc 360 0x7f9bff564670 [1736:1952] (15 24)! 262 | + calloc 32 0x7f9bff564030 [32:72] (1 32) #3183 168 131 1 0 84 0 263 | /lib64/libdl.so.2(+0x1960)[0x7f9bfcfa8960] 264 | /lib64/libdl.so.2(dlsym+0x5a)[0x7f9bfcfa843a] 265 | /home/sam/devel/log-malloc2/scripts/../.libs/liblog-malloc2.so(+0x12e3)[0x7f9bfd7882e3] 266 | /lib64/ld-linux-x86-64.so.2(+0xfa0b)[0x7f9bfd99ba0b] 267 | /lib64/ld-linux-x86-64.so.2(+0xfb1c)[0x7f9bfd99bb1c] 268 | /lib64/ld-linux-x86-64.so.2(+0x140a)[0x7f9bfd98d40a] 269 | /lib64/libdl.so.2(+0x13a0)[0x7f9bfcfa83a0] 270 | # PID 23451 271 | # EXE /home/sam/devel/log-malloc2/examples/leak-01 272 | # CWD /home/sam/devel/log-malloc2 273 | + INIT [1736:1952] malloc=3 calloc=3 realloc=0 memalign=0/0 valloc=0 free=0 274 | + malloc 2000 0x7f9bff564800 [3736:3992] #3183 168 131 1 0 84 0 275 | ./examples/leak-01(main+0x32)[0x7f9bfdbb1af2] 276 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f9bfd3f01cb] 277 | ./examples/leak-01(+0x9a9)[0x7f9bfdbb19a9] 278 | [0x0] 279 | + malloc 100 0x7f9bff565000 [3836:4128] #3183 168 131 1 0 84 0 280 | ./examples/leak-01(main+0x40)[0x7f9bfdbb1b00] 281 | /lib64/libc.so.6(__libc_start_main+0x11b)[0x7f9bfd3f01cb] 282 | ./examples/leak-01(+0x9a9)[0x7f9bfdbb19a9] 283 | [0x0] 284 | + free -100 0x7f9bff565000 [3736:3992] #3183 168 131 1 0 84 0 285 | + FINI [3736:3992] malloc=5 calloc=3 realloc=0 memalign=0/0 valloc=0 free=1 286 | # FILE /proc/self/maps 287 | 7f9bfcd90000-7f9bfcda6000 r-xp 00000000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 288 | 7f9bfcda6000-7f9bfcfa5000 ---p 00016000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 289 | 7f9bfcfa5000-7f9bfcfa6000 r--p 00015000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 290 | 7f9bfcfa6000-7f9bfcfa7000 rw-p 00016000 fe:02 911050 /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.3/libgcc_s.so.1 291 | 7f9bfcfa7000-7f9bfcfaa000 r-xp 00000000 fe:02 819448 /lib64/libdl-2.19.so 292 | 7f9bfcfaa000-7f9bfd1a9000 ---p 00003000 fe:02 819448 /lib64/libdl-2.19.so 293 | 7f9bfd1a9000-7f9bfd1aa000 r--p 00002000 fe:02 819448 /lib64/libdl-2.19.so 294 | 7f9bfd1aa000-7f9bfd1ab000 rw-p 00003000 fe:02 819448 /lib64/libdl-2.19.so 295 | 7f9bfd1ab000-7f9bfd1c5000 r-xp 00000000 fe:02 818913 /lib64/libpthread-2.19.so 296 | 7f9bfd1c5000-7f9bfd3c5000 ---p 0001a000 fe:02 818913 /lib64/libpthread-2.19.so 297 | 7f9bfd3c5000-7f9bfd3c6000 r--p 0001a000 fe:02 818913 /lib64/libpthread-2.19.so 298 | 7f9bfd3c6000-7f9bfd3c7000 rw-p 0001b000 fe:02 818913 /lib64/libpthread-2.19.so 299 | 7f9bfd3c7000-7f9bfd3cb000 rw-p 00000000 00:00 0 300 | 7f9bfd3cb000-7f9bfd57d000 r-xp 00000000 fe:02 819451 /lib64/libc-2.19.so 301 | 7f9bfd57d000-7f9bfd77d000 ---p 001b2000 fe:02 819451 /lib64/libc-2.19.so 302 | 7f9bfd77d000-7f9bfd781000 r--p 001b2000 fe:02 819451 /lib64/libc-2.19.so 303 | 7f9bfd781000-7f9bfd783000 rw-p 001b6000 fe:02 819451 /lib64/libc-2.19.so 304 | 7f9bfd783000-7f9bfd787000 rw-p 00000000 00:00 0 305 | 7f9bfd787000-7f9bfd78b000 r-xp 00000000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 306 | 7f9bfd78b000-7f9bfd98a000 ---p 00004000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 307 | 7f9bfd98a000-7f9bfd98b000 r--p 00003000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 308 | 7f9bfd98b000-7f9bfd98c000 rw-p 00004000 fe:02 14619 /home/sam/devel/log-malloc2/.libs/liblog-malloc2.so.1.0.0 309 | 7f9bfd98c000-7f9bfd9ae000 r-xp 00000000 fe:02 818908 /lib64/ld-2.19.so 310 | 7f9bfdb99000-7f9bfdb9d000 rw-p 00000000 00:00 0 311 | 7f9bfdbad000-7f9bfdbae000 rw-p 00000000 00:00 0 312 | 7f9bfdbae000-7f9bfdbaf000 r--p 00022000 fe:02 818908 /lib64/ld-2.19.so 313 | 7f9bfdbaf000-7f9bfdbb0000 rw-p 00023000 fe:02 818908 /lib64/ld-2.19.so 314 | 7f9bfdbb0000-7f9bfdbb1000 rw-p 00000000 00:00 0 315 | 7f9bfdbb1000-7f9bfdbb2000 r-xp 00000000 fe:02 15340 /home/sam/devel/log-malloc2/examples/leak-01 316 | 7f9bfddb1000-7f9bfddb2000 r--p 00000000 fe:02 15340 /home/sam/devel/log-malloc2/examples/leak-01 317 | 7f9bfddb2000-7f9bfddb3000 rw-p 00001000 fe:02 15340 /home/sam/devel/log-malloc2/examples/leak-01 318 | 7f9bff564000-7f9bff585000 rw-p 00000000 00:00 0 [heap] 319 | 7fffb5471000-7fffb5493000 rw-p 00000000 00:00 0 [stack] 320 | 7fffb54cf000-7fffb54d1000 r-xp 00000000 00:00 0 [vdso] 321 | ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 322 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2011-01-19.21; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | # Protect names problematic for `test' and other utilities. 160 | case $dst_arg in 161 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 162 | esac 163 | shift;; 164 | 165 | -T) no_target_directory=true;; 166 | 167 | --version) echo "$0 $scriptversion"; exit $?;; 168 | 169 | --) shift 170 | break;; 171 | 172 | -*) echo "$0: invalid option: $1" >&2 173 | exit 1;; 174 | 175 | *) break;; 176 | esac 177 | shift 178 | done 179 | 180 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 181 | # When -d is used, all remaining arguments are directories to create. 182 | # When -t is used, the destination is already specified. 183 | # Otherwise, the last argument is the destination. Remove it from $@. 184 | for arg 185 | do 186 | if test -n "$dst_arg"; then 187 | # $@ is not empty: it contains at least $arg. 188 | set fnord "$@" "$dst_arg" 189 | shift # fnord 190 | fi 191 | shift # arg 192 | dst_arg=$arg 193 | # Protect names problematic for `test' and other utilities. 194 | case $dst_arg in 195 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 196 | esac 197 | done 198 | fi 199 | 200 | if test $# -eq 0; then 201 | if test -z "$dir_arg"; then 202 | echo "$0: no input file specified." >&2 203 | exit 1 204 | fi 205 | # It's OK to call `install-sh -d' without argument. 206 | # This can happen when creating conditional directories. 207 | exit 0 208 | fi 209 | 210 | if test -z "$dir_arg"; then 211 | do_exit='(exit $ret); exit $ret' 212 | trap "ret=129; $do_exit" 1 213 | trap "ret=130; $do_exit" 2 214 | trap "ret=141; $do_exit" 13 215 | trap "ret=143; $do_exit" 15 216 | 217 | # Set umask so as not to create temps with too-generous modes. 218 | # However, 'strip' requires both read and write access to temps. 219 | case $mode in 220 | # Optimize common cases. 221 | *644) cp_umask=133;; 222 | *755) cp_umask=22;; 223 | 224 | *[0-7]) 225 | if test -z "$stripcmd"; then 226 | u_plus_rw= 227 | else 228 | u_plus_rw='% 200' 229 | fi 230 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 231 | *) 232 | if test -z "$stripcmd"; then 233 | u_plus_rw= 234 | else 235 | u_plus_rw=,u+rw 236 | fi 237 | cp_umask=$mode$u_plus_rw;; 238 | esac 239 | fi 240 | 241 | for src 242 | do 243 | # Protect names problematic for `test' and other utilities. 244 | case $src in 245 | -* | [=\(\)!]) src=./$src;; 246 | esac 247 | 248 | if test -n "$dir_arg"; then 249 | dst=$src 250 | dstdir=$dst 251 | test -d "$dstdir" 252 | dstdir_status=$? 253 | else 254 | 255 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 256 | # might cause directories to be created, which would be especially bad 257 | # if $src (and thus $dsttmp) contains '*'. 258 | if test ! -f "$src" && test ! -d "$src"; then 259 | echo "$0: $src does not exist." >&2 260 | exit 1 261 | fi 262 | 263 | if test -z "$dst_arg"; then 264 | echo "$0: no destination specified." >&2 265 | exit 1 266 | fi 267 | dst=$dst_arg 268 | 269 | # If destination is a directory, append the input filename; won't work 270 | # if double slashes aren't ignored. 271 | if test -d "$dst"; then 272 | if test -n "$no_target_directory"; then 273 | echo "$0: $dst_arg: Is a directory" >&2 274 | exit 1 275 | fi 276 | dstdir=$dst 277 | dst=$dstdir/`basename "$src"` 278 | dstdir_status=0 279 | else 280 | # Prefer dirname, but fall back on a substitute if dirname fails. 281 | dstdir=` 282 | (dirname "$dst") 2>/dev/null || 283 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 284 | X"$dst" : 'X\(//\)[^/]' \| \ 285 | X"$dst" : 'X\(//\)$' \| \ 286 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 287 | echo X"$dst" | 288 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 289 | s//\1/ 290 | q 291 | } 292 | /^X\(\/\/\)[^/].*/{ 293 | s//\1/ 294 | q 295 | } 296 | /^X\(\/\/\)$/{ 297 | s//\1/ 298 | q 299 | } 300 | /^X\(\/\).*/{ 301 | s//\1/ 302 | q 303 | } 304 | s/.*/./; q' 305 | ` 306 | 307 | test -d "$dstdir" 308 | dstdir_status=$? 309 | fi 310 | fi 311 | 312 | obsolete_mkdir_used=false 313 | 314 | if test $dstdir_status != 0; then 315 | case $posix_mkdir in 316 | '') 317 | # Create intermediate dirs using mode 755 as modified by the umask. 318 | # This is like FreeBSD 'install' as of 1997-10-28. 319 | umask=`umask` 320 | case $stripcmd.$umask in 321 | # Optimize common cases. 322 | *[2367][2367]) mkdir_umask=$umask;; 323 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 324 | 325 | *[0-7]) 326 | mkdir_umask=`expr $umask + 22 \ 327 | - $umask % 100 % 40 + $umask % 20 \ 328 | - $umask % 10 % 4 + $umask % 2 329 | `;; 330 | *) mkdir_umask=$umask,go-w;; 331 | esac 332 | 333 | # With -d, create the new directory with the user-specified mode. 334 | # Otherwise, rely on $mkdir_umask. 335 | if test -n "$dir_arg"; then 336 | mkdir_mode=-m$mode 337 | else 338 | mkdir_mode= 339 | fi 340 | 341 | posix_mkdir=false 342 | case $umask in 343 | *[123567][0-7][0-7]) 344 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 345 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 346 | ;; 347 | *) 348 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 349 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 350 | 351 | if (umask $mkdir_umask && 352 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 353 | then 354 | if test -z "$dir_arg" || { 355 | # Check for POSIX incompatibilities with -m. 356 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 357 | # other-writeable bit of parent directory when it shouldn't. 358 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 359 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 360 | case $ls_ld_tmpdir in 361 | d????-?r-*) different_mode=700;; 362 | d????-?--*) different_mode=755;; 363 | *) false;; 364 | esac && 365 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 366 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 367 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 368 | } 369 | } 370 | then posix_mkdir=: 371 | fi 372 | rmdir "$tmpdir/d" "$tmpdir" 373 | else 374 | # Remove any dirs left behind by ancient mkdir implementations. 375 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 376 | fi 377 | trap '' 0;; 378 | esac;; 379 | esac 380 | 381 | if 382 | $posix_mkdir && ( 383 | umask $mkdir_umask && 384 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 385 | ) 386 | then : 387 | else 388 | 389 | # The umask is ridiculous, or mkdir does not conform to POSIX, 390 | # or it failed possibly due to a race condition. Create the 391 | # directory the slow way, step by step, checking for races as we go. 392 | 393 | case $dstdir in 394 | /*) prefix='/';; 395 | [-=\(\)!]*) prefix='./';; 396 | *) prefix='';; 397 | esac 398 | 399 | eval "$initialize_posix_glob" 400 | 401 | oIFS=$IFS 402 | IFS=/ 403 | $posix_glob set -f 404 | set fnord $dstdir 405 | shift 406 | $posix_glob set +f 407 | IFS=$oIFS 408 | 409 | prefixes= 410 | 411 | for d 412 | do 413 | test X"$d" = X && continue 414 | 415 | prefix=$prefix$d 416 | if test -d "$prefix"; then 417 | prefixes= 418 | else 419 | if $posix_mkdir; then 420 | (umask=$mkdir_umask && 421 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 422 | # Don't fail if two instances are running concurrently. 423 | test -d "$prefix" || exit 1 424 | else 425 | case $prefix in 426 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 427 | *) qprefix=$prefix;; 428 | esac 429 | prefixes="$prefixes '$qprefix'" 430 | fi 431 | fi 432 | prefix=$prefix/ 433 | done 434 | 435 | if test -n "$prefixes"; then 436 | # Don't fail if two instances are running concurrently. 437 | (umask $mkdir_umask && 438 | eval "\$doit_exec \$mkdirprog $prefixes") || 439 | test -d "$dstdir" || exit 1 440 | obsolete_mkdir_used=true 441 | fi 442 | fi 443 | fi 444 | 445 | if test -n "$dir_arg"; then 446 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 447 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 448 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 449 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 450 | else 451 | 452 | # Make a couple of temp file names in the proper directory. 453 | dsttmp=$dstdir/_inst.$$_ 454 | rmtmp=$dstdir/_rm.$$_ 455 | 456 | # Trap to clean up those temp files at exit. 457 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 458 | 459 | # Copy the file name to the temp name. 460 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 461 | 462 | # and set any options; do chmod last to preserve setuid bits. 463 | # 464 | # If any of these fail, we abort the whole thing. If we want to 465 | # ignore errors from any of these, just make sure not to ignore 466 | # errors from the above "$doit $cpprog $src $dsttmp" command. 467 | # 468 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 469 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 470 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 471 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 472 | 473 | # If -C, don't bother to copy if it wouldn't change the file. 474 | if $copy_on_change && 475 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 476 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 477 | 478 | eval "$initialize_posix_glob" && 479 | $posix_glob set -f && 480 | set X $old && old=:$2:$4:$5:$6 && 481 | set X $new && new=:$2:$4:$5:$6 && 482 | $posix_glob set +f && 483 | 484 | test "$old" = "$new" && 485 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 486 | then 487 | rm -f "$dsttmp" 488 | else 489 | # Rename the file to the real destination. 490 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 491 | 492 | # The rename failed, perhaps because mv can't rename something else 493 | # to itself, or perhaps because mv is so ancient that it does not 494 | # support -f. 495 | { 496 | # Now remove or move aside any old file at destination location. 497 | # We try this two ways since rm can't unlink itself on some 498 | # systems and the destination file might be busy for other 499 | # reasons. In this case, the final cleanup might fail but the new 500 | # file should still install successfully. 501 | { 502 | test ! -f "$dst" || 503 | $doit $rmcmd -f "$dst" 2>/dev/null || 504 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 505 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 506 | } || 507 | { echo "$0: cannot unlink or rename $dst" >&2 508 | (exit 1); exit 1 509 | } 510 | } && 511 | 512 | # Now rename the file to the real destination. 513 | $doit $mvcmd "$dsttmp" "$dst" 514 | } 515 | fi || exit 1 516 | 517 | trap '' 0 518 | fi 519 | done 520 | 521 | # Local variables: 522 | # eval: (add-hook 'write-file-hooks 'time-stamp) 523 | # time-stamp-start: "scriptversion=" 524 | # time-stamp-format: "%:y-%02m-%02d.%02H" 525 | # time-stamp-time-zone: "UTC" 526 | # time-stamp-end: "; # UTC" 527 | # End: 528 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, 5 | Inc. 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without warranty of any kind. 11 | 12 | Basic Installation 13 | ================== 14 | 15 | Briefly, the shell commands `./configure; make; make install' should 16 | configure, build, and install this package. The following 17 | more-detailed instructions are generic; see the `README' file for 18 | instructions specific to this package. Some packages provide this 19 | `INSTALL' file but do not implement all of the features documented 20 | below. The lack of an optional feature in a given package is not 21 | necessarily a bug. More recommendations for GNU packages can be found 22 | in *note Makefile Conventions: (standards)Makefile Conventions. 23 | 24 | The `configure' shell script attempts to guess correct values for 25 | various system-dependent variables used during compilation. It uses 26 | those values to create a `Makefile' in each directory of the package. 27 | It may also create one or more `.h' files containing system-dependent 28 | definitions. Finally, it creates a shell script `config.status' that 29 | you can run in the future to recreate the current configuration, and a 30 | file `config.log' containing compiler output (useful mainly for 31 | debugging `configure'). 32 | 33 | It can also use an optional file (typically called `config.cache' 34 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 35 | the results of its tests to speed up reconfiguring. Caching is 36 | disabled by default to prevent problems with accidental use of stale 37 | cache files. 38 | 39 | If you need to do unusual things to compile the package, please try 40 | to figure out how `configure' could check whether to do them, and mail 41 | diffs or instructions to the address given in the `README' so they can 42 | be considered for the next release. If you are using the cache, and at 43 | some point `config.cache' contains results you don't want to keep, you 44 | may remove or edit it. 45 | 46 | The file `configure.ac' (or `configure.in') is used to create 47 | `configure' by a program called `autoconf'. You need `configure.ac' if 48 | you want to change it or regenerate `configure' using a newer version 49 | of `autoconf'. 50 | 51 | The simplest way to compile this package is: 52 | 53 | 1. `cd' to the directory containing the package's source code and type 54 | `./configure' to configure the package for your system. 55 | 56 | Running `configure' might take a while. While running, it prints 57 | some messages telling which features it is checking for. 58 | 59 | 2. Type `make' to compile the package. 60 | 61 | 3. Optionally, type `make check' to run any self-tests that come with 62 | the package, generally using the just-built uninstalled binaries. 63 | 64 | 4. Type `make install' to install the programs and any data files and 65 | documentation. When installing into a prefix owned by root, it is 66 | recommended that the package be configured and built as a regular 67 | user, and only the `make install' phase executed with root 68 | privileges. 69 | 70 | 5. Optionally, type `make installcheck' to repeat any self-tests, but 71 | this time using the binaries in their final installed location. 72 | This target does not install anything. Running this target as a 73 | regular user, particularly if the prior `make install' required 74 | root privileges, verifies that the installation completed 75 | correctly. 76 | 77 | 6. You can remove the program binaries and object files from the 78 | source code directory by typing `make clean'. To also remove the 79 | files that `configure' created (so you can compile the package for 80 | a different kind of computer), type `make distclean'. There is 81 | also a `make maintainer-clean' target, but that is intended mainly 82 | for the package's developers. If you use it, you may have to get 83 | all sorts of other programs in order to regenerate files that came 84 | with the distribution. 85 | 86 | 7. Often, you can also type `make uninstall' to remove the installed 87 | files again. In practice, not all packages have tested that 88 | uninstallation works correctly, even though it is required by the 89 | GNU Coding Standards. 90 | 91 | 8. Some packages, particularly those that use Automake, provide `make 92 | distcheck', which can by used by developers to test that all other 93 | targets like `make install' and `make uninstall' work correctly. 94 | This target is generally not run by end users. 95 | 96 | Compilers and Options 97 | ===================== 98 | 99 | Some systems require unusual options for compilation or linking that 100 | the `configure' script does not know about. Run `./configure --help' 101 | for details on some of the pertinent environment variables. 102 | 103 | You can give `configure' initial values for configuration parameters 104 | by setting variables in the command line or in the environment. Here 105 | is an example: 106 | 107 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 108 | 109 | *Note Defining Variables::, for more details. 110 | 111 | Compiling For Multiple Architectures 112 | ==================================== 113 | 114 | You can compile the package for more than one kind of computer at the 115 | same time, by placing the object files for each architecture in their 116 | own directory. To do this, you can use GNU `make'. `cd' to the 117 | directory where you want the object files and executables to go and run 118 | the `configure' script. `configure' automatically checks for the 119 | source code in the directory that `configure' is in and in `..'. This 120 | is known as a "VPATH" build. 121 | 122 | With a non-GNU `make', it is safer to compile the package for one 123 | architecture at a time in the source code directory. After you have 124 | installed the package for one architecture, use `make distclean' before 125 | reconfiguring for another architecture. 126 | 127 | On MacOS X 10.5 and later systems, you can create libraries and 128 | executables that work on multiple system types--known as "fat" or 129 | "universal" binaries--by specifying multiple `-arch' options to the 130 | compiler but only a single `-arch' option to the preprocessor. Like 131 | this: 132 | 133 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 134 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 135 | CPP="gcc -E" CXXCPP="g++ -E" 136 | 137 | This is not guaranteed to produce working output in all cases, you 138 | may have to build one architecture at a time and combine the results 139 | using the `lipo' tool if you have problems. 140 | 141 | Installation Names 142 | ================== 143 | 144 | By default, `make install' installs the package's commands under 145 | `/usr/local/bin', include files under `/usr/local/include', etc. You 146 | can specify an installation prefix other than `/usr/local' by giving 147 | `configure' the option `--prefix=PREFIX', where PREFIX must be an 148 | absolute file name. 149 | 150 | You can specify separate installation prefixes for 151 | architecture-specific files and architecture-independent files. If you 152 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 153 | PREFIX as the prefix for installing programs and libraries. 154 | Documentation and other data files still use the regular prefix. 155 | 156 | In addition, if you use an unusual directory layout you can give 157 | options like `--bindir=DIR' to specify different values for particular 158 | kinds of files. Run `configure --help' for a list of the directories 159 | you can set and what kinds of files go in them. In general, the 160 | default for these options is expressed in terms of `${prefix}', so that 161 | specifying just `--prefix' will affect all of the other directory 162 | specifications that were not explicitly provided. 163 | 164 | The most portable way to affect installation locations is to pass the 165 | correct locations to `configure'; however, many packages provide one or 166 | both of the following shortcuts of passing variable assignments to the 167 | `make install' command line to change installation locations without 168 | having to reconfigure or recompile. 169 | 170 | The first method involves providing an override variable for each 171 | affected directory. For example, `make install 172 | prefix=/alternate/directory' will choose an alternate location for all 173 | directory configuration variables that were expressed in terms of 174 | `${prefix}'. Any directories that were specified during `configure', 175 | but not in terms of `${prefix}', must each be overridden at install 176 | time for the entire installation to be relocated. The approach of 177 | makefile variable overrides for each directory variable is required by 178 | the GNU Coding Standards, and ideally causes no recompilation. 179 | However, some platforms have known limitations with the semantics of 180 | shared libraries that end up requiring recompilation when using this 181 | method, particularly noticeable in packages that use GNU Libtool. 182 | 183 | The second method involves providing the `DESTDIR' variable. For 184 | example, `make install DESTDIR=/alternate/directory' will prepend 185 | `/alternate/directory' before all installation names. The approach of 186 | `DESTDIR' overrides is not required by the GNU Coding Standards, and 187 | does not work on platforms that have drive letters. On the other hand, 188 | it does better at avoiding recompilation issues, and works well even 189 | when some directory options were not specified in terms of `${prefix}' 190 | at `configure' time. 191 | 192 | Optional Features 193 | ================= 194 | 195 | If the package supports it, you can cause programs to be installed 196 | with an extra prefix or suffix on their names by giving `configure' the 197 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 198 | 199 | Some packages pay attention to `--enable-FEATURE' options to 200 | `configure', where FEATURE indicates an optional part of the package. 201 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 202 | is something like `gnu-as' or `x' (for the X Window System). The 203 | `README' should mention any `--enable-' and `--with-' options that the 204 | package recognizes. 205 | 206 | For packages that use the X Window System, `configure' can usually 207 | find the X include and library files automatically, but if it doesn't, 208 | you can use the `configure' options `--x-includes=DIR' and 209 | `--x-libraries=DIR' to specify their locations. 210 | 211 | Some packages offer the ability to configure how verbose the 212 | execution of `make' will be. For these packages, running `./configure 213 | --enable-silent-rules' sets the default to minimal output, which can be 214 | overridden with `make V=1'; while running `./configure 215 | --disable-silent-rules' sets the default to verbose, which can be 216 | overridden with `make V=0'. 217 | 218 | Particular systems 219 | ================== 220 | 221 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 222 | CC is not installed, it is recommended to use the following options in 223 | order to use an ANSI C compiler: 224 | 225 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 226 | 227 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 228 | 229 | HP-UX `make' updates targets which have the same time stamps as 230 | their prerequisites, which makes it generally unusable when shipped 231 | generated files such as `configure' are involved. Use GNU `make' 232 | instead. 233 | 234 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 235 | parse its `' header file. The option `-nodtk' can be used as 236 | a workaround. If GNU CC is not installed, it is therefore recommended 237 | to try 238 | 239 | ./configure CC="cc" 240 | 241 | and if that doesn't work, try 242 | 243 | ./configure CC="cc -nodtk" 244 | 245 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 246 | directory contains several dysfunctional programs; working variants of 247 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 248 | in your `PATH', put it _after_ `/usr/bin'. 249 | 250 | On Haiku, software installed for all users goes in `/boot/common', 251 | not `/usr/local'. It is recommended to use the following options: 252 | 253 | ./configure --prefix=/boot/common 254 | 255 | Specifying the System Type 256 | ========================== 257 | 258 | There may be some features `configure' cannot figure out 259 | automatically, but needs to determine by the type of machine the package 260 | will run on. Usually, assuming the package is built to be run on the 261 | _same_ architectures, `configure' can figure that out, but if it prints 262 | a message saying it cannot guess the machine type, give it the 263 | `--build=TYPE' option. TYPE can either be a short name for the system 264 | type, such as `sun4', or a canonical name which has the form: 265 | 266 | CPU-COMPANY-SYSTEM 267 | 268 | where SYSTEM can have one of these forms: 269 | 270 | OS 271 | KERNEL-OS 272 | 273 | See the file `config.sub' for the possible values of each field. If 274 | `config.sub' isn't included in this package, then this package doesn't 275 | need to know the machine type. 276 | 277 | If you are _building_ compiler tools for cross-compiling, you should 278 | use the option `--target=TYPE' to select the type of system they will 279 | produce code for. 280 | 281 | If you want to _use_ a cross compiler, that generates code for a 282 | platform different from the build platform, you should specify the 283 | "host" platform (i.e., that on which the generated programs will 284 | eventually be run) with `--host=TYPE'. 285 | 286 | Sharing Defaults 287 | ================ 288 | 289 | If you want to set default values for `configure' scripts to share, 290 | you can create a site shell script called `config.site' that gives 291 | default values for variables like `CC', `cache_file', and `prefix'. 292 | `configure' looks for `PREFIX/share/config.site' if it exists, then 293 | `PREFIX/etc/config.site' if it exists. Or, you can set the 294 | `CONFIG_SITE' environment variable to the location of the site script. 295 | A warning: not all `configure' scripts look for a site script. 296 | 297 | Defining Variables 298 | ================== 299 | 300 | Variables not defined in a site shell script can be set in the 301 | environment passed to `configure'. However, some packages may run 302 | configure again during the build, and the customized values of these 303 | variables may be lost. In order to avoid this problem, you should set 304 | them in the `configure' command line, using `VAR=value'. For example: 305 | 306 | ./configure CC=/usr/local2/bin/gcc 307 | 308 | causes the specified `gcc' to be used as the C compiler (unless it is 309 | overridden in the site shell script). 310 | 311 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 312 | an Autoconf bug. Until the bug is fixed you can use this workaround: 313 | 314 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 315 | 316 | `configure' Invocation 317 | ====================== 318 | 319 | `configure' recognizes the following options to control how it 320 | operates. 321 | 322 | `--help' 323 | `-h' 324 | Print a summary of all of the options to `configure', and exit. 325 | 326 | `--help=short' 327 | `--help=recursive' 328 | Print a summary of the options unique to this package's 329 | `configure', and exit. The `short' variant lists options used 330 | only in the top level, while the `recursive' variant lists options 331 | also present in any nested packages. 332 | 333 | `--version' 334 | `-V' 335 | Print the version of Autoconf used to generate the `configure' 336 | script, and exit. 337 | 338 | `--cache-file=FILE' 339 | Enable the cache: use and save the results of the tests in FILE, 340 | traditionally `config.cache'. FILE defaults to `/dev/null' to 341 | disable caching. 342 | 343 | `--config-cache' 344 | `-C' 345 | Alias for `--cache-file=config.cache'. 346 | 347 | `--quiet' 348 | `--silent' 349 | `-q' 350 | Do not print messages saying which checks are being made. To 351 | suppress all normal output, redirect it to `/dev/null' (any error 352 | messages will still be shown). 353 | 354 | `--srcdir=DIR' 355 | Look for the package's source code in directory DIR. Usually 356 | `configure' can determine that directory automatically. 357 | 358 | `--prefix=DIR' 359 | Use DIR as the installation prefix. *note Installation Names:: 360 | for more details, including other options available for fine-tuning 361 | the installation locations. 362 | 363 | `--no-create' 364 | `-n' 365 | Run the configure checks, but stop before creating any output 366 | files. 367 | 368 | `configure' also accepts some other, not widely useful, options. Run 369 | `configure --help' for more details. 370 | 371 | -------------------------------------------------------------------------------- /scripts/backtrace2line.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # log-malloc2 / backtrace2line 4 | # Translate backtrace() output into functions, file names and line numbers (supports ASLR) 5 | # 6 | # Author: Samuel Behan <_samuel_._behan_(at)_dob_._sk> (C) 2013-2015 7 | # 8 | # License: GNU GPLv3 (http://www.gnu.org/licenses/gpl.html) 9 | # 10 | # Web: 11 | # http://devel.dob.sk/log-malloc2 12 | # http://blog.dob.sk/category/devel/log-malloc2 (howto, tutorials) 13 | # https://github.com/samsk/log-malloc2 (git repo) 14 | # 15 | # 16 | package log_malloc::backtrace2line; 17 | 18 | use strict; 19 | use Cwd; 20 | use Getopt::Long; 21 | use Pod::Usage; 22 | use Data::Dumper; 23 | use File::Basename; 24 | 25 | # VERSION 26 | our $VERSION = '0.4'; 27 | 28 | # CONFIGS 29 | our $VERBOSE = 0; 30 | our $WARNING = 0; # set to -1 to disable globally 31 | my @ADDR2LINE = ("addr2line", "-C"); 32 | my $LINUX_ALSR_CONFIG = "/proc/sys/kernel/randomize_va_space"; 33 | 34 | # EXEC 35 | sub main(@); 36 | exit(main(@ARGV)) if(!caller()); 37 | 38 | # 39 | # INTERNAL FUNCTIONS 40 | # 41 | 42 | sub addr2num($) 43 | { 44 | my ($addr) = @_; 45 | 46 | no warnings 'portable'; 47 | return hex($addr); 48 | } 49 | 50 | sub readFile($) 51 | { 52 | my ($fd) = @_; 53 | 54 | my @arr; 55 | while(my $line = <$fd>) 56 | { 57 | chomp($line); 58 | 59 | # read till line with only '.' or beginning with '=' 60 | last 61 | if($line =~ /^(\.$|=)/o); 62 | 63 | push(@arr, $line); 64 | } 65 | return @arr; 66 | } 67 | 68 | sub verbose($$) 69 | { 70 | my ($lev, $msg) = @_; 71 | 72 | return print(STDERR $msg) 73 | if($lev <= $VERBOSE); 74 | return 0; 75 | } 76 | 77 | sub read_mapsFile($$) 78 | { 79 | my ($mapsFile, $pid) = @_; 80 | 81 | # mapsFile can be an ARRAY (for moduline call) 82 | if(ref($mapsFile) eq 'ARRAY') 83 | { 84 | return @$mapsFile; 85 | } 86 | elsif($pid) 87 | { 88 | $mapsFile = sprintf("/proc/%d/maps", $pid); 89 | } 90 | elsif(ref($mapsFile)) 91 | { 92 | die("[programming error] invalid mapsFile=$mapsFile argument !"); 93 | } 94 | 95 | # read from user supplied maps file 96 | my $fd; 97 | return () 98 | if(!$mapsFile || (!open($fd, $mapsFile))); 99 | 100 | my @maps = readFile($fd); 101 | close($fd); 102 | 103 | return @maps; 104 | } 105 | 106 | sub get_libmap(@) 107 | { 108 | my (@maps) = @_; 109 | 110 | no warnings 'portable'; 111 | my %libs; 112 | foreach my $line (@maps) 113 | { 114 | my ($range, $perms, $offset, $dev, $inode, $path) = split(/\s+/o, $line); 115 | my ($addr_from, $addr_to) = split(/-/o, $range); 116 | 117 | # need only executable sections 118 | next 119 | if($perms !~ /x/o || !$path || $path =~ /^\[\w+\]$/o); 120 | 121 | # unhex 122 | $addr_from = addr2num($addr_from); 123 | $addr_to = addr2num($addr_to); 124 | 125 | my $libname = basename($path); 126 | $libs{$libname} = $addr_from; 127 | $libs{'-' . $libname} = $path; 128 | 129 | $libs{$addr_from} = $addr_to; 130 | $libs{$addr_to} = $path; 131 | } 132 | # all-in-one hash (not very effective, but who cares here :) 133 | # basename => addr_from 134 | # -basename => absolute-path 135 | # addr_from => addr_to 136 | # addr_to => absolute-path 137 | return %libs; 138 | } 139 | 140 | sub get_wd($$) 141 | { 142 | my ($wd, $pid) = @_; 143 | 144 | return $wd || undef 145 | if($wd || !$pid); 146 | 147 | my $lnk = sprintf("/proc/%d/cwd", $pid); 148 | return readlink($lnk); 149 | } 150 | 151 | sub addr2libname(\%$) 152 | { 153 | my ($libmap, $addr) = @_; 154 | 155 | foreach my $addr_from (keys(%$libmap)) 156 | { 157 | my $addr_to = $libmap->{$addr_from}; 158 | 159 | # dummy format, filter it 160 | next 161 | if($addr_from !~ /^[[:digit:]]+$/o || $addr_to !~ /^[[:digit:]]+$/o); 162 | 163 | # check range 164 | next 165 | if($addr <= $addr_from || $addr >= $addr_to); 166 | 167 | return ($libmap->{$addr_to}, $addr_from); 168 | } 169 | return undef; 170 | } 171 | 172 | # 173 | # PUBLIC FUNCTIONS 174 | # 175 | 176 | # addr2lime(@executable, @symbols): @resolved_symbols 177 | sub addr2line($@) 178 | { 179 | my ($exe, @symbols) = @_; 180 | 181 | my @cmd = (@ADDR2LINE, "-f", "-e", $exe, @symbols); 182 | 183 | # XXX: improve this 184 | my @lines = `@cmd`; 185 | warn("\t - addr2line filed while executing '@cmd'\n"), return () 186 | if($? != 0); 187 | 188 | my %addr; 189 | my $symIdx = 0; 190 | chomp(@lines); 191 | for(my $ii = 0; $ii <= $#lines; $ii++) 192 | { 193 | my $line = $lines[$ii]; 194 | my $sym = $symbols[$symIdx]; 195 | 196 | # every 1st line is function 197 | my $function = $line; 198 | my $location = $lines[++$ii]; 199 | 200 | if($function eq "??" && $location eq "??:0") 201 | { 202 | $addr{$sym || $symIdx} = undef; 203 | } 204 | else 205 | { 206 | my ($f, $l) = split(/:/o, $location, 2); 207 | 208 | $addr{$sym || $symIdx} = { function => $function, file => $f, line => $l }; 209 | } 210 | 211 | $symIdx++; 212 | } 213 | 214 | return %addr; 215 | } 216 | 217 | # process($mapsFile, $workingDir, $pid, @symbols): @resolved_symbols 218 | sub process($$$@) 219 | { 220 | my ($mapsFile, $wd, $pid, @symbols) = @_; 221 | 222 | # get wordkir 223 | my $cwd = get_wd($wd, $pid); 224 | 225 | # get library map from maps file 226 | my (@maps, %libs); 227 | @maps = read_mapsFile($mapsFile, $pid); 228 | if(@maps) 229 | { 230 | %libs = get_libmap(@maps); 231 | return wantarray ? (undef, "failed to get library maps") : undef 232 | if(!keys(%libs)); 233 | } 234 | 235 | # parse input 236 | my @data; 237 | foreach my $sym (@symbols) 238 | { 239 | my $retry = 0; 240 | 241 | chomp($sym); 242 | push(@data, $sym); # as fallback return input symbol 243 | 244 | next if($sym eq "[0x0]"); 245 | verbose(1, "SYM_PARSE_FAILED: $sym\n"), next 246 | if(!($sym =~ /^\s*((.*?)\((.*?)\))?\[(.*?)\]\s*$/o)); 247 | my ($exe, $offset, $addr) = ($2, $3, $4); 248 | 249 | my $libOffset = 0; 250 | my $addrNum = addr2num($addr); 251 | 252 | if($exe && $exe ne '*') 253 | { 254 | my $exeBN = basename($exe); 255 | 256 | # try to find absolute path via maps file 257 | $exe = $libs{'-' . $exeBN} 258 | if(exists($libs{'-' . $exeBN})); 259 | 260 | # not asolute path yet (try it with work-dir) 261 | my $exeOld = $exe; 262 | if($cwd && $exe !~ /^\//o) 263 | { 264 | my $exe2 = $cwd . '/' . $exe; 265 | $exe2 = Cwd::abs_path($exe2); 266 | 267 | verbose(1, "EXE_ABSPATH_FAILED: $exe\n"), next 268 | if(!$exe2 || ! -e $exe2); 269 | $exe = $exe2; 270 | } 271 | 272 | verbose(1, "EXE_NOT_FOUND: $exeOld\n"), next 273 | if(!$exe || !-f $exe); 274 | 275 | # need real file not symlink 276 | $exeOld = $exe; 277 | while(defined($exe) && -l $exe && $retry++ < 10) 278 | { 279 | my $dir = dirname($exe); 280 | 281 | $exeOld = $exe; 282 | $exe = readlink($exe); 283 | 284 | $exe = $dir . '/' . $exe 285 | if($dir && $exe && $exe !~ /^\//o); 286 | } 287 | 288 | verbose(1, "EXE_SYMLINK_FOLLOW_FAILED: $exeOld\n"), next 289 | if(!defined($exe)); 290 | 291 | # get absolute path 292 | $exe = Cwd::abs_path($exe); 293 | 294 | verbose(1, "EXE_NOT_FOUND: $exe\n"), next 295 | if(!-f $exe); 296 | 297 | # library offset via basename 298 | $exeBN = basename($exe); 299 | $libOffset = $libs{$exeBN} 300 | if(exists($libs{$exeBN})); 301 | } 302 | else 303 | { 304 | if($WARNING == 0 && !%libs) 305 | { 306 | warn("WARNING: incomplete SYMBOL (without libname), but no --pid or --maps-file provided !\n"); 307 | $WARNING = 1; 308 | } 309 | 310 | ($exe, $libOffset) = addr2libname(%libs, $addrNum); 311 | 312 | verbose(1, "ADDR_NOT_MAPPED: $addr\n"), next 313 | if(!$exe); 314 | 315 | verbose(1, "EXE_NOT_FOUND: $exe\n"), next 316 | if(!-f $exe); 317 | } 318 | 319 | # addr offset 320 | my $addrReal = $addrNum - $libOffset; 321 | my $addrHex = sprintf("0x%02x", $addrReal); 322 | 323 | # success 324 | pop(@data); 325 | push(@data, { exe => $exe, offset => $offset, addr_sym => $addr, 326 | addr_num => $addrNum, addr_real => $addrReal, 327 | addr_hex => $addrHex, 328 | sym => $sym }); 329 | } 330 | 331 | # group translate 332 | my @lines; 333 | for(my $ii = 0; $ii <= $#data; $ii++) 334 | { 335 | my $rec = $data[$ii]; 336 | 337 | push(@lines, $rec), next 338 | if(!ref($rec) || !exists($rec->{exe})); 339 | 340 | # collect all addr from same exe 341 | my %translate = ( $rec->{addr_hex} => $ii); 342 | for(my $oo = $ii; $oo <= $#data; $oo++) 343 | { 344 | next 345 | if(!ref($data[$oo]) 346 | || !exists($data[$oo]->{exe}) 347 | || $data[$oo]->{exe} ne $rec->{exe}); 348 | $translate{ $data[$oo]->{addr_hex} } = $oo; 349 | } 350 | 351 | # translate from exe 352 | my %translated = addr2line($rec->{exe}, keys(%translate)); 353 | push(@lines, $rec), next 354 | if(!keys(%translated)); 355 | 356 | # update data list 357 | foreach my $addr (keys(%translated)) 358 | { 359 | my $idx = $translate{ $addr }; 360 | die("[programming error]") 361 | if(!defined($idx)); 362 | 363 | # not translated 364 | $data[$idx] = $data[$idx]->{sym}, next 365 | if(!$translated{ $addr }); 366 | 367 | my $sym = $data[$idx]->{sym}; 368 | $data[$idx] = $translated{ $addr }; 369 | $data[$idx]->{sym} = $sym; 370 | } 371 | 372 | # current record translated 373 | if(defined($data[$ii])) 374 | { push(@lines, $data[$ii]); } 375 | else # resolve failed 376 | { push(@lines, $rec->{sym}); } 377 | } 378 | 379 | return @lines; 380 | } 381 | 382 | # checkASLR(): bool 383 | sub checkASLR() 384 | { 385 | my $enabled = 0; 386 | 387 | # LINUX randomization check 388 | if(-e $LINUX_ALSR_CONFIG 389 | && open(my $fd, $LINUX_ALSR_CONFIG)) 390 | { 391 | my $value = <$fd>; 392 | 393 | close($fd); 394 | 395 | # value is non-zero 396 | # 0 - no randomization 397 | # 1 - randomize libs, stack, mmap, VDSO, heap 398 | # 2 - also brk() 399 | $enabled = ($value != 0); 400 | } 401 | return $enabled; 402 | } 403 | 404 | # 405 | # MAIN 406 | # 407 | 408 | sub main(@) 409 | { 410 | my (@argv) = @_; 411 | my ($exe, $pid, $mapsFile, $workDir, @symbols, $fullName, $man, $help); 412 | 413 | @ARGV = @argv; 414 | GetOptions( 415 | "<>" => sub { push(@symbols, "$_[0]"); }, 416 | "p|pid=i" => \$pid, 417 | "m|maps-file=s" => \$mapsFile, 418 | "wd|work-dir=s" => \$workDir, 419 | "full-filename" => \$fullName, 420 | "demangle=s" => sub { push(@ADDR2LINE, "--demangle=$_[1]"); }, 421 | "v|verbose" => \$VERBOSE, 422 | "h|?|help" => \$help, 423 | "man" => \$man, 424 | ) || pod2usage( -verbose => 0, -exitval => 1 ); 425 | @argv = @ARGV; 426 | 427 | pod2usage( -verbose => 1 ) 428 | if($help); 429 | pod2usage( -verbose => 3 ) 430 | if($man); 431 | 432 | # read from STDIN or from file 433 | if(!@symbols || 434 | (my $symFile = ($#symbols == 0 && -e $symbols[0]))) 435 | { 436 | my $fd = \*STDIN; 437 | 438 | die("$0: failed to open symbols file '$symbols[0]' - $!\n") 439 | if($symFile && $symbols[0] ne "-" && !open($fd, $symbols[0])); 440 | 441 | # read symbols 442 | @symbols = readFile($fd); 443 | 444 | # read maps 445 | if(!$mapsFile || ($mapsFile && $mapsFile eq "-")) 446 | { 447 | $mapsFile = []; 448 | @$mapsFile = readFile($fd); 449 | } 450 | 451 | close($fd); 452 | } 453 | 454 | # ASLR check 455 | warn("WARNING: ASLR enabled, but no --pid or --maps-file provided !\n") 456 | if(checkASLR() && (!$pid && !$mapsFile) && $WARNING >= 0); 457 | 458 | # process symbols now 459 | my @data = process($mapsFile, $workDir, $pid, @symbols); 460 | 461 | # error 462 | die("$0: $data[1]\n") 463 | if(!defined($data[0])); 464 | 465 | foreach my $rec (@data) 466 | { 467 | if(ref($rec)) 468 | { 469 | my $file = $rec->{file}; 470 | $file = basename($file) 471 | if(!$fullName); 472 | 473 | printf("%s at %s:%s\n", $rec->{function}, $file, $rec->{line}); 474 | } 475 | else 476 | { 477 | printf("%s (TRANSLATE FAILED)\n", $rec); 478 | } 479 | } 480 | 481 | return 0; 482 | } 483 | 484 | 1; 485 | 486 | =pod 487 | 488 | =head1 NAME 489 | 490 | backtrace2line - convert libc() backtrace() output into file names and line numbers. 491 | 492 | =head1 SYNOPSIS 493 | 494 | backtrace2line [ OPTIONS ] [ I ... I ] 495 | 496 | backtrace2line [ OPTIONS ] I 497 | 498 | =head1 DESCRIPTION 499 | 500 | This script converts output of backtrace_symbols() or backtrace_symbols_fd() into file names and line numbers. 501 | It also supports conversion of backtraces produces on machines with an active ASLR (Address space layout randomization), 502 | if pid or process memory map is provided (/proc//maps). 503 | 504 | NOTE: This script can be also used as perl module. 505 | 506 | =head1 ARGUMENTS 507 | 508 | =over 4 509 | 510 | =item I 511 | 512 | Path to backtrace file. This file must contain symbols (one per line) and I contain also content of 513 | the maps file, divided by line with single dot (see B) or line begging with '=' character. 514 | The same applies if reading backtrace from stdin. 515 | 516 | =item I 517 | 518 | Symbol as generated by backtrace_symbols() function (ie. ./leak-01(main+0x40)[0x7f00ad7a4b00]). 519 | 520 | =back 521 | 522 | =head1 OPTIONS 523 | 524 | =over 4 525 | 526 | =item B<-p> I 527 | 528 | =item B<--pid> I 529 | 530 | Pid of a B running process, that generated given backtrace (needed only if ASLR active or 531 | if backtrace sumbol contains no library, like when libunwind is used). 532 | Pid is used to get process memory map (from /proc//maps). 533 | 534 | =item B<-m> I 535 | 536 | =item B<--maps-file> I 537 | 538 | Path to a file with process memory map of a backtraced process. This is required if ALSR is 539 | active or if backtrace has been generated by libunwind. 540 | Data from maps file is used to identify functions location (IP is checked against mapped range) 541 | or to find full path of the application/libraries from symbol(s). 542 | 543 | =item B<-wd> I 544 | 545 | =item B<--work-dir> I 546 | 547 | Original work or start dir of backtraced process (needed only if backtrace contains relative paths, 548 | and maps file has not been provided). 549 | 550 | =item B<--demangle> I