Fixed building with glibc 2.34 where malloc/free hooks have been removed.

Removed mtrace.c file since it is not used (it seems it was a base for
ktrace.c).

Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
pull/12/head
Michele Calgaro 3 years ago
parent 5adfbc2372
commit f4582480b4
Signed by: MicheleC
GPG Key ID: 2A75B7CA8ADED5CF

@ -1,8 +1,6 @@
This is a KDE tool to assist with malloc debugging using glibc's "mtrace"
functionality. Unfortunately the mtrace that is part of current (9/9/2000)
glibc versions only logs the return-address of the malloc/free call.
The file mtrace.c in this directory logs a complete backtrace upon malloc/
free.
THIS PROGRAM DEPENDS ON GLIBC! It does not pretend to be portable.

@ -112,27 +112,36 @@ void kuntrace(void);
static void addAllocationToTree(void);
static void tr_freehook __P ((void*, const void*));
static void* tr_reallochook __P ((void*, size_t,
const void*));
static void* tr_mallochook __P ((size_t, const void*));
/* Old hook values. */
static void (*tr_old_free_hook) __P ((void* ptr, const void*));
static void* (*tr_old_malloc_hook) __P ((size_t size,
const void*));
static void* (*tr_old_realloc_hook) __P ((void* ptr,
size_t size,
const void*));
// Pointers to real calls
static void* (*real_malloc_ptr) (size_t size) = NULL;
static void* (*real_realloc_ptr) (void *ptr, size_t size) = NULL;
static void (*real_free_ptr) (void *ptr) = NULL;
// This is used to return "allocated" memory until the pointer
// to the real malloc function becomes known.
// It seems about 75k of memory are required before that happens,
// but the buffer provides more space to cater for more if needed
// in other OS.
#define MALLOC_INIT_SIZE (1024 * 256)
static char malloc_init_buf[MALLOC_INIT_SIZE];
static size_t malloc_init_pos = 0;
static pthread_mutex_t malloc_init_lock = PTHREAD_MUTEX_INITIALIZER;
static FILE* mallstream;
static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
static pthread_mutex_t malloc_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t free_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t realloc_lock = PTHREAD_MUTEX_INITIALIZER;
/* Address to breakpoint on accesses to... */
void* mallwatch;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static int tr_malloc_hook_enabled = 0;
static int tr_realloc_hook_enabled = 0;
static int tr_free_hook_enabled = 0;
// Hooks active in this thread
static __thread int tr_malloc_hook_active = 0;
static __thread int tr_realloc_hook_active = 0;
static __thread int tr_free_hook_active = 0;
static int bt_size;
static void *bt[TR_BT_SIZE + 1];
@ -159,14 +168,15 @@ static char* mallTreeFile = NULL;
static FILE* mallTreeStream = NULL;
static long mallThreshold = 2000;
/* This function is called when the block being alloc'd, realloc'd, or
* freed has an address matching the variable "mallwatch". In a
* debugger, set "mallwatch" to the address of interest, then put a
* breakpoint on tr_break. */
void tr_break __P ((void));
void
tr_break()
// Get real function pointers on loading
static void __attribute__((constructor)) init(void)
{
if (!real_malloc_ptr)
{
real_malloc_ptr = (void* (*)(size_t))(dlsym(RTLD_NEXT, "malloc"));
real_realloc_ptr = (void* (*)(void *, size_t))(dlsym(RTLD_NEXT, "realloc"));
real_free_ptr = (void (*)(void *))(dlsym(RTLD_NEXT, "free"));
}
}
__inline__ static void
@ -373,104 +383,125 @@ tr_log(const void* caller, void* ptr, void* old,
}
}
static void
tr_freehook (ptr, caller)
void* ptr;
const void* caller;
void free(void *ptr)
{
if (ptr == NULL)
if (ptr == NULL ||
(ptr >= (void*)malloc_init_buf && ptr < (void*)(malloc_init_buf + malloc_init_pos)))
{
return;
if (ptr == mallwatch)
tr_break ();
}
if (!real_free_ptr)
{
// Should never happen!
return;
}
if (!tr_free_hook_enabled || tr_free_hook_active)
{
// Real function is called if hooks are not enabled or if
// free is called recursively while logging data (should
// probably never happen!)
return (*real_free_ptr)(ptr);
}
pthread_mutex_lock(&free_lock);
tr_free_hook_active = 1;
pthread_mutex_lock(&lock);
#ifdef PROFILE
tr_frees++;
tr_current_mallocs--;
#endif
__free_hook = tr_old_free_hook;
if (tr_old_free_hook != NULL)
(*tr_old_free_hook) (ptr, caller);
else
free(ptr);
void *caller = __builtin_return_address(0);
(*real_free_ptr)(ptr);
tr_log(caller, ptr, 0, 0, TR_FREE);
__free_hook = tr_freehook;
pthread_mutex_unlock(&lock);
tr_free_hook_active = 0;
pthread_mutex_unlock(&free_lock);
}
static void*
tr_mallochook (size, caller)
size_t size;
const void* caller;
void *malloc(size_t size)
{
void* hdr;
if (!real_malloc_ptr)
{
// Return memory from static buffer if available
pthread_mutex_lock(&malloc_init_lock);
if ((malloc_init_pos + size) > MALLOC_INIT_SIZE)
{
pthread_mutex_unlock(&malloc_init_lock);
return NULL;
}
else
{
void *ptr = (void*)(malloc_init_buf + malloc_init_pos);
malloc_init_pos += size;
pthread_mutex_unlock(&malloc_init_lock);
return ptr;
}
}
pthread_mutex_lock(&lock);
if (!tr_malloc_hook_enabled || tr_malloc_hook_active)
{
// Real function is called if hooks are not enabled or if
// malloc is called recursively while logging data
return (*real_malloc_ptr)(size);
}
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
__free_hook = tr_old_free_hook;
pthread_mutex_lock(&malloc_lock);
tr_malloc_hook_active = 1;
if (tr_old_malloc_hook != NULL)
hdr = (void*) (*tr_old_malloc_hook) (size, caller);
else
hdr = (void*) malloc(size);
void *caller = __builtin_return_address(0);
void *hdr = (*real_malloc_ptr)(size);
tr_log(caller, hdr, 0, size, TR_MALLOC);
/* We only build the allocation tree if mallTreeFile has been set. */
if (mallTreeFile)
addAllocationToTree();
__malloc_hook = tr_mallochook;
__realloc_hook = tr_reallochook;
__free_hook = tr_freehook;
#ifdef PROFILE
tr_mallocs++;
tr_current_mallocs++;
if (tr_current_mallocs > tr_max_mallocs)
tr_max_mallocs = tr_current_mallocs;
#endif
pthread_mutex_unlock(&lock);
if (hdr == mallwatch)
tr_break ();
tr_malloc_hook_active = 0;
pthread_mutex_unlock(&malloc_lock);
return hdr;
}
static void*
tr_reallochook (ptr, size, caller)
void* ptr;
size_t size;
const void* caller;
void* realloc(void *ptr, size_t size)
{
void* hdr;
if (ptr == mallwatch)
tr_break ();
if (ptr >= (void*)malloc_init_buf && ptr < (void*)(malloc_init_buf + malloc_init_pos))
{
// Reallocating pointer from initial static buffer, nothing to free. Just call malloc
return malloc(size);
}
pthread_mutex_lock(&lock);
if (!real_realloc_ptr)
{
// Should never happen
return NULL;
}
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
if (!tr_realloc_hook_enabled || tr_realloc_hook_active)
{
// Real function is called if hooks are not enabled or if
// realloc is called recursively while logging data
return (*real_realloc_ptr)(ptr, size);
}
if (tr_old_realloc_hook != NULL)
hdr = (void*) (*tr_old_realloc_hook) (ptr, size, caller);
else
hdr = (void*) realloc (ptr, size);
pthread_mutex_lock(&realloc_lock);
tr_realloc_hook_active = 1;
void *caller = __builtin_return_address(0);
void *hdr = (*real_realloc_ptr)(ptr, size);
tr_log(caller, hdr, ptr, size, TR_REALLOC);
__free_hook = tr_freehook;
__malloc_hook = tr_mallochook;
__realloc_hook = tr_reallochook;
#ifdef PROFILE
/* If ptr is 0 there was no previos malloc of this location */
// If ptr is 0 there was no previos malloc of this location
if (ptr == NULL)
{
tr_mallocs++;
@ -480,10 +511,8 @@ tr_reallochook (ptr, size, caller)
}
#endif
pthread_mutex_unlock(&lock);
if (hdr == mallwatch)
tr_break ();
tr_realloc_hook_active = 0;
pthread_mutex_unlock(&realloc_lock);
return hdr;
}
@ -671,10 +700,7 @@ release_libc_mem (void)
#endif
/* We enable tracing if either the environment variable MALLOC_TRACE
* or the variable MALLOC_TREE are set, or if the variable mallwatch
* has been patched to an address that the debugging user wants us to
* stop on. When patching mallwatch, don't forget to set a breakpoint
* on tr_break! */
* or the variable MALLOC_TREE are set */
void
ktrace()
{
@ -701,7 +727,7 @@ ktrace()
if( getenv("MALLOC_THRESHOLD") != NULL )
mallThreshold = atol(getenv("MALLOC_THRESHOLD"));
#endif
if (mallfile != NULL || mallTreeFile != NULL || mallwatch != NULL)
if (mallfile != NULL || mallTreeFile != NULL)
{
mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
if (mallstream != NULL)
@ -717,14 +743,10 @@ ktrace()
if(*buf)
fprintf (mallstream, "#%s\n", buf);
/* Save old hooks and hook in our own functions for all
* malloc, realloc and free calls */
tr_old_free_hook = __free_hook;
__free_hook = tr_freehook;
tr_old_malloc_hook = __malloc_hook;
__malloc_hook = tr_mallochook;
tr_old_realloc_hook = __realloc_hook;
__realloc_hook = tr_reallochook;
// Enable hooks
tr_malloc_hook_enabled = 1;
tr_realloc_hook_enabled = 1;
tr_free_hook_enabled = 1;
tr_cache_pos = TR_CACHE_SIZE;
do
@ -748,14 +770,14 @@ ktrace()
void
kuntrace()
{
// Disable hooks
tr_malloc_hook_enabled = 0;
tr_realloc_hook_enabled = 0;
tr_free_hook_enabled = 0;
if (mallstream == NULL)
return;
/* restore hooks to original values */
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
if (removeBranchesBelowThreshold(CallTree))
CallTree = 0;
if (mallTreeFile)
@ -802,9 +824,6 @@ int fork()
{
close(fileno(mallstream));
mallstream = NULL;
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
}
}
return result;

@ -1,383 +0,0 @@
/* More debugging hooks for `malloc'.
Copyright (C) 1991,92,93,94,96,97,98,99,2000 Free Software Foundation, Inc.
Written April 2, 1991 by John Gilmore of Cygnus Support.
Based on mcheck.c by Mike Haertel.
Hacked by AK
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
The author may be reached (Email) at the address mike@ai.mit.edu,
or (US mail) as Mike Haertel c/o Free Software Foundation. */
#define _LIBC
#define MALLOC_HOOKS
#ifndef _MALLOC_INTERNAL
#define _MALLOC_INTERNAL
#include <malloc.h>
#include <mcheck.h>
#include <bits/libc-lock.h>
#endif
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio-common/_itoa.h>
#include <elf/ldsodefs.h>
#ifdef USE_IN_LIBIO
# include <libio/iolibio.h>
# define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
#endif
#define TRACE_BUFFER_SIZE 512
static FILE *mallstream;
static const char mallenv[]= "MALLOC_TRACE";
static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
__libc_lock_define_initialized (static, lock)
/* Address to breakpoint on accesses to... */
__ptr_t mallwatch;
/* File name and line number information, for callers that had
the foresight to call through a macro. */
char *_mtrace_file;
int _mtrace_line;
/* Old hook values. */
static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
const __ptr_t));
static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
__malloc_size_t size,
const __ptr_t));
#define TR_PIPELINE_SIZE 16
#define TR_BT_SIZE 80
#define TR_HASHTABLE_SIZE 9973
#define TR_NONE 0
#define TR_MALLOC 1
#define TR_REALLOC 2
#define TR_FREE 3
typedef struct {
int op;
__ptr_t ptr;
__ptr_t old;
__malloc_size_t size;
int bt_size;
void *bt[TR_BT_SIZE+1];
} tr_entry;
static tr_entry tr_pipeline[TR_PIPELINE_SIZE];
static int tr_pipeline_pos;
static void *tr_hashtable[TR_HASHTABLE_SIZE];
/* This function is called when the block being alloc'd, realloc'd, or
freed has an address matching the variable "mallwatch". In a debugger,
set "mallwatch" to the address of interest, then put a breakpoint on
tr_break. */
void tr_break __P ((void));
void
tr_break ()
{
}
static void
tr_backtrace(void **bt, int size)
{
char buf[20];
int i;
Dl_info info;
for(i = 0; i < size; i++)
{
long hash = (((unsigned long)bt[i]) / 4) % TR_HASHTABLE_SIZE;
if ((tr_hashtable[hash]!= bt[i]) && _dl_addr(bt[i], &info) && info.dli_fname && *info.dli_fname)
{
if (bt[i] >= (void *) info.dli_saddr)
sprintf(buf, "+%#lx", (unsigned long)(bt[i] - info.dli_saddr));
else
sprintf(buf, "-%#lx", (unsigned long)(info.dli_saddr - bt[i]));
fprintf(mallstream, "%s%s%s%s%s[%p]\n",
info.dli_fname ?: "",
info.dli_sname ? "(" : "",
info.dli_sname ?: "",
info.dli_sname ? buf : "",
info.dli_sname ? ")" : "",
bt[i]);
tr_hashtable[hash] = bt[i];
}
else {
fprintf(mallstream, "[%p]\n", bt[i]);
}
}
}
static void
inline
tr_log(const __ptr_t caller, __ptr_t ptr, __ptr_t old, __malloc_size_t size, int op)
{
switch(op)
{
case TR_REALLOC:
break;
case TR_MALLOC:
break;
case TR_FREE:
{
int i = tr_pipeline_pos;
do {
if (i) i--; else i = TR_PIPELINE_SIZE-1;
if (tr_pipeline[i].ptr == ptr)
{
if (tr_pipeline[i].op == TR_MALLOC)
{
tr_pipeline[i].op = TR_NONE;
tr_pipeline[i].ptr = NULL;
return;
}
break;
}
} while (i != tr_pipeline_pos);
}
}
if (tr_pipeline[tr_pipeline_pos].op)
{
putc('@', mallstream);
putc('\n', mallstream);
/* Generate backtrace...
* We throw out the first frame (tr_mallochook)
* end the last one (_start)
*/
tr_backtrace(&(tr_pipeline[tr_pipeline_pos].bt[1]),
tr_pipeline[tr_pipeline_pos].bt_size-2);
switch(tr_pipeline[tr_pipeline_pos].op)
{
case TR_MALLOC:
fprintf (mallstream, "+ %p %#lx\n",
tr_pipeline[tr_pipeline_pos].ptr,
(unsigned long int) tr_pipeline[tr_pipeline_pos].size);
break;
case TR_FREE:
fprintf (mallstream, "- %p\n",
tr_pipeline[tr_pipeline_pos].ptr);
break;
case TR_REALLOC:
fprintf (mallstream, "< %p\n",
tr_pipeline[tr_pipeline_pos].old);
fprintf (mallstream, "> %p %#lx\n",
tr_pipeline[tr_pipeline_pos].ptr,
(unsigned long int) tr_pipeline[tr_pipeline_pos].size);
break;
}
}
tr_pipeline[tr_pipeline_pos].op = op;
tr_pipeline[tr_pipeline_pos].ptr = ptr;
tr_pipeline[tr_pipeline_pos].old = old;
tr_pipeline[tr_pipeline_pos].size = size;
tr_pipeline[tr_pipeline_pos].bt_size = backtrace(
tr_pipeline[tr_pipeline_pos].bt, TR_BT_SIZE);
tr_pipeline_pos++;
if (tr_pipeline_pos == TR_PIPELINE_SIZE)
tr_pipeline_pos = 0;
}
static void tr_freehook __P ((__ptr_t, const __ptr_t));
static void
tr_freehook (ptr, caller)
__ptr_t ptr;
const __ptr_t caller;
{
if (ptr == NULL)
return;
__libc_lock_lock (lock);
tr_log(caller, ptr, 0, 0, TR_FREE );
__libc_lock_unlock (lock);
if (ptr == mallwatch)
tr_break ();
__libc_lock_lock (lock);
__free_hook = tr_old_free_hook;
if (tr_old_free_hook != NULL)
(*tr_old_free_hook) (ptr, caller);
else
free (ptr);
__free_hook = tr_freehook;
__libc_lock_unlock (lock);
}
static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
static __ptr_t
tr_mallochook (size, caller)
__malloc_size_t size;
const __ptr_t caller;
{
__ptr_t hdr;
__libc_lock_lock (lock);
__malloc_hook = tr_old_malloc_hook;
if (tr_old_malloc_hook != NULL)
hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
else
hdr = (__ptr_t) malloc (size);
__malloc_hook = tr_mallochook;
tr_log(caller, hdr, 0, size, TR_MALLOC);
__libc_lock_unlock (lock);
if (hdr == mallwatch)
tr_break ();
return hdr;
}
static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
static __ptr_t
tr_reallochook (ptr, size, caller)
__ptr_t ptr;
__malloc_size_t size;
const __ptr_t caller;
{
__ptr_t hdr;
if (ptr == mallwatch)
tr_break ();
__libc_lock_lock (lock);
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
if (tr_old_realloc_hook != NULL)
hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
else
hdr = (__ptr_t) realloc (ptr, size);
__free_hook = tr_freehook;
__malloc_hook = tr_mallochook;
__realloc_hook = tr_reallochook;
tr_log(caller, hdr, ptr, size, TR_REALLOC);
__libc_lock_unlock (lock);
if (hdr == mallwatch)
tr_break ();
return hdr;
}
#ifdef _LIBC
extern void __libc_freeres (void);
/* This function gets called to make sure all memory the library
allocates get freed and so does not irritate the user when studying
the mtrace output. */
static void
release_libc_mem (void)
{
/* Only call the free function if we still are running in mtrace mode. */
if (mallstream != NULL)
__libc_freeres ();
}
#endif
/* We enable tracing if either the environment variable MALLOC_TRACE
is set, or if the variable mallwatch has been patched to an address
that the debugging user wants us to stop on. When patching mallwatch,
don't forget to set a breakpoint on tr_break! */
void
mtrace ()
{
#ifdef _LIBC
static int added_atexit_handler;
#endif
char *mallfile;
/* Don't panic if we're called more than once. */
if (mallstream != NULL)
return;
#ifdef _LIBC
/* When compiling the GNU libc we use the secure getenv function
which prevents the misuse in case of SUID or SGID enabled
programs. */
mallfile = __secure_getenv (mallenv);
#else
mallfile = getenv (mallenv);
#endif
if (mallfile != NULL || mallwatch != NULL)
{
mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
if (mallstream != NULL)
{
/* Be sure it doesn't malloc its buffer! */
setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
fprintf (mallstream, "= Start\n");
tr_old_free_hook = __free_hook;
__free_hook = tr_freehook;
tr_old_malloc_hook = __malloc_hook;
__malloc_hook = tr_mallochook;
tr_old_realloc_hook = __realloc_hook;
__realloc_hook = tr_reallochook;
tr_pipeline_pos = TR_PIPELINE_SIZE;
for(;tr_pipeline_pos--;)
{
tr_pipeline[tr_pipeline_pos].op = TR_NONE;
tr_pipeline[tr_pipeline_pos].ptr = NULL;
}
memset(tr_hashtable, 0, sizeof(void *)*TR_HASHTABLE_SIZE);
#ifdef _LIBC
if (!added_atexit_handler)
{
added_atexit_handler = 1;
atexit (release_libc_mem);
}
#endif
}
}
}
void
muntrace ()
{
if (mallstream == NULL)
return;
fprintf (mallstream, "= End\n");
fclose (mallstream);
mallstream = NULL;
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
}
Loading…
Cancel
Save