mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 750290 - Remove tools/leaky. r=dbaron
This commit is contained in:
parent
28ffb279a2
commit
e551920d94
@ -111,7 +111,6 @@ MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@
|
||||
MOZ_EXTENSIONS = @MOZ_EXTENSIONS@
|
||||
MOZ_JSDEBUGGER = @MOZ_JSDEBUGGER@
|
||||
MOZ_IPDL_TESTS = @MOZ_IPDL_TESTS@
|
||||
MOZ_LEAKY = @MOZ_LEAKY@
|
||||
MOZ_MEMORY = @MOZ_MEMORY@
|
||||
MOZ_PROFILING = @MOZ_PROFILING@
|
||||
MOZ_ENABLE_PROFILER_SPS = @MOZ_ENABLE_PROFILER_SPS@
|
||||
|
10
configure.in
10
configure.in
@ -6471,15 +6471,6 @@ MOZ_ARG_ENABLE_BOOL(update-packaging,
|
||||
MOZ_UPDATE_PACKAGING= )
|
||||
AC_SUBST(MOZ_UPDATE_PACKAGING)
|
||||
|
||||
dnl ========================================================
|
||||
dnl leaky
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(leaky,
|
||||
[ --enable-leaky Build leaky memory tool],
|
||||
MOZ_LEAKY=1,
|
||||
MOZ_LEAKY=)
|
||||
|
||||
|
||||
dnl ========================================================
|
||||
dnl build the tests by default
|
||||
dnl ========================================================
|
||||
@ -8416,7 +8407,6 @@ AC_SUBST(WARNINGS_AS_ERRORS)
|
||||
AC_SUBST(MOZ_EXTENSIONS)
|
||||
AC_SUBST(MOZ_JSDEBUGGER)
|
||||
AC_SUBST(MOZ_LOG_REFCNT)
|
||||
AC_SUBST(MOZ_LEAKY)
|
||||
AC_SUBST(MOZ_ENABLE_PROFILER_SPS)
|
||||
AC_SUBST(MOZ_JPROF)
|
||||
AC_SUBST(MOZ_SHARK)
|
||||
|
@ -82,7 +82,6 @@ MOZ_DEBUG_FLAGS = @MOZ_DEBUG_FLAGS@
|
||||
MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@
|
||||
MOZ_EXTENSIONS = @MOZ_EXTENSIONS@
|
||||
MOZ_JSDEBUGGER = @MOZ_JSDEBUGGER@
|
||||
MOZ_LEAKY = @MOZ_LEAKY@
|
||||
MOZ_MEMORY = @MOZ_MEMORY@
|
||||
MOZ_PROFILING = @MOZ_PROFILING@
|
||||
MOZ_JPROF = @MOZ_JPROF@
|
||||
|
@ -4813,7 +4813,6 @@ AC_SUBST(MOZ_DEBUG_DISABLE_DEFS)
|
||||
AC_SUBST(MOZ_DEBUG_FLAGS)
|
||||
AC_SUBST(MOZ_DEBUG_LDFLAGS)
|
||||
AC_SUBST(WARNINGS_AS_ERRORS)
|
||||
AC_SUBST(MOZ_LEAKY)
|
||||
AC_SUBST(MOZ_JPROF)
|
||||
AC_SUBST(MOZ_SHARK)
|
||||
AC_SUBST(MOZ_CALLGRIND)
|
||||
|
@ -1531,12 +1531,6 @@ if [ "$MOZ_JPROF" ]; then
|
||||
"
|
||||
fi
|
||||
|
||||
if [ "$MOZ_LEAKY" ]; then
|
||||
add_makefiles "
|
||||
tools/leaky/Makefile
|
||||
"
|
||||
fi
|
||||
|
||||
if [ "$NS_TRACE_MALLOC" ]; then
|
||||
add_makefiles "
|
||||
tools/trace-malloc/Makefile
|
||||
|
@ -265,10 +265,6 @@ tier_platform_dirs += toolkit/system/dbus
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef MOZ_LEAKY
|
||||
tier_platform_dirs += tools/leaky
|
||||
endif
|
||||
|
||||
ifdef MOZ_MAPINFO
|
||||
tier_platform_dirs += tools/codesighs
|
||||
endif
|
||||
|
@ -1,54 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kipp E.B. Hickman <kipp@netscape.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "TestPreload.h"
|
||||
#include "config.h"
|
||||
#include <malloc.h>
|
||||
|
||||
// This is a fake implementation of malloc that layers on top of the
|
||||
// native platforms malloc routine (ideally using weak symbols). What
|
||||
// it does if given a specail size request it returns a fake address
|
||||
// result, otherwise it uses the underlying malloc.
|
||||
void* malloc(size_t aSize)
|
||||
{
|
||||
if (aSize == LD_PRELOAD_TEST_MALLOC_SIZE) {
|
||||
return (void*) LD_PRELOAD_TEST_VALUE;
|
||||
}
|
||||
else {
|
||||
return REAL_MALLOC(aSize);
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
#! gmake
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Kipp E.B. Hickman.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2001
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
SIMPLE_PROGRAMS = TestLeaky TestPreload ShowLibs
|
||||
|
||||
PROGRAM = leaky
|
||||
|
||||
CPPSRCS = \
|
||||
bfd.cpp \
|
||||
coff.cpp \
|
||||
dict.cpp \
|
||||
elf.cpp \
|
||||
leaky.cpp \
|
||||
strset.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
||||
LIBS = \
|
||||
-lbfd \
|
||||
-liberty \
|
||||
$(NULL)
|
||||
|
||||
RESOURCES = \
|
||||
leaky.css \
|
||||
leaky.js \
|
||||
open.gif \
|
||||
open-over.gif \
|
||||
close.gif \
|
||||
close-over.gif \
|
||||
$(NULL)
|
||||
|
||||
RESOURCES := $(addprefix $(srcdir)/, $(RESOURCES))
|
||||
|
||||
# Stuff to build the library used to wrap malloc
|
||||
LIBMALLOC_CPPSRCS = libmalloc.cpp
|
||||
LIBMALLOC_OBJECTS = $(LIBMALLOC_CPPSRCS:.cpp=.o)
|
||||
LIBMALLOC = libleaky.so
|
||||
|
||||
# Stuff to build test programs
|
||||
LIBPRELOAD_CPPSRCS = LibPreload.cpp
|
||||
LIBPRELOAD_OBJECTS = $(LIBPRELOAD_CPPSRCS:.cpp=.o)
|
||||
LIBPRELOAD = libpreload.so
|
||||
|
||||
# include $(topsrcdir)/config/config.mk
|
||||
|
||||
OTHER_LIBRARIES = $(LIBMALLOC) $(LIBPRELOAD)
|
||||
TARGETS := $(PROGRAM) $(SIMPLE_PROGRAMS) $(OTHER_LIBRARIES)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# Make sure all depends on files that rules.mk doesn't know about.
|
||||
all:: $(OTHER_LIBRARIES)
|
||||
|
||||
# Make sure install depends on files that rules.mk doesn't know about.
|
||||
libs:: $(OTHER_LIBRARIES)
|
||||
|
||||
# Make sure libs depends on files that rules.mk doesn't know about.
|
||||
libs:: $(OTHER_LIBRARIES)
|
||||
|
||||
clobber::
|
||||
rm -f $(LIBMALLOC_OBJECTS) $(LIBPRELOAD_OBJECTS)
|
||||
rm -f $(LIBMALLOC) $(LIBPRELOAD)
|
||||
rm -f $(SIMPLE_PROGRAMS:=.o)
|
||||
|
||||
clean::
|
||||
rm -f $(LIBMALLOC_OBJECTS) $(LIBPRELOAD_OBJECTS)
|
||||
|
||||
$(LIBMALLOC): $(LIBMALLOC_OBJECTS)
|
||||
rm -f $@
|
||||
$(MKSHLIB) $(LIBMALLOC_OBJECTS)
|
||||
|
||||
$(LIBPRELOAD): $(LIBPRELOAD_OBJECTS)
|
||||
$(MKSHLIB) $(LIBPRELOAD_OBJECTS)
|
||||
|
||||
test:
|
||||
@echo LIBMALLOC = $(LIBMALLOC)
|
||||
@echo LIBPRELOAD = $(LIBPRELOAD)
|
||||
@echo TARGETS = $(TARGETS)
|
||||
|
||||
libs:: $(OTHER_LIBRARIES) $(RESOURCES)
|
||||
$(INSTALL) -m 555 $(OTHER_LIBRARIES) $(DIST)/lib
|
||||
$(INSTALL) $(RESOURCES) $(DIST)/bin/res/leaky
|
@ -1,100 +0,0 @@
|
||||
#! gmake
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Kipp E.B. Hickman.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1999
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
CXX = c++
|
||||
OPTIMIZER = -g
|
||||
CXXFLAGS = $(OPTIMIZER) -Wall -Wp,-MD,.deps-$<
|
||||
CXXF = $(CXX) $(CXXFLAGS)
|
||||
|
||||
MKSHLIB = $(CXX) -shared
|
||||
|
||||
# Stuff to build the leaky executable
|
||||
LEAKY_CPPSRCS = \
|
||||
bfd.cpp \
|
||||
coff.cpp \
|
||||
dict.cpp \
|
||||
elf.cpp \
|
||||
leaky.cpp \
|
||||
strset.cpp \
|
||||
$(NULL)
|
||||
LEAKY_OBJECTS = $(LEAKY_CPPSRCS:.cpp=.o)
|
||||
LEAKY_LIBS = -lbfd -liberty
|
||||
|
||||
# Stuff to build the library used to wrap malloc
|
||||
LIBMALLOC_CPPSRCS = libmalloc.cpp
|
||||
LIBMALLOC_OBJECTS = $(LIBMALLOC_CPPSRCS:.cpp=.o)
|
||||
LIBMALLOC = libleaky.so
|
||||
|
||||
# Stuff to build test programs
|
||||
LIBPRELOAD = libpreload.so
|
||||
|
||||
TARGETS = leaky $(LIBMALLOC) TestLeaky TestPreload $(LIBPRELOAD) ShowLibs
|
||||
|
||||
.SUFFIXES: .cpp
|
||||
|
||||
default all: $(TARGETS)
|
||||
|
||||
clean:
|
||||
rm -f core malloc-log malloc-map *.o .deps*
|
||||
|
||||
clobber: clean
|
||||
rm -f $(TARGETS)
|
||||
|
||||
.cpp.o:
|
||||
$(CXXF) -c $<
|
||||
|
||||
leaky: $(LEAKY_OBJECTS)
|
||||
$(CXXF) -o $@ $(LEAKY_OBJECTS) $(LEAKY_LIBS)
|
||||
|
||||
$(LIBMALLOC): $(LIBMALLOC_OBJECTS)
|
||||
rm -f $@
|
||||
$(MKSHLIB) -o $@ $(LIBMALLOC_OBJECTS)
|
||||
|
||||
TestLeaky: TestLeaky.cpp
|
||||
$(CXXF) -o $@ TestLeaky.cpp
|
||||
|
||||
TestPreload: TestPreload.cpp
|
||||
$(CXXF) -o $@ TestPreload.cpp
|
||||
|
||||
$(LIBPRELOAD): LibPreload.o
|
||||
$(MKSHLIB) -o $@ LibPreload.o
|
||||
|
||||
ShowLibs: ShowLibs.cpp
|
||||
$(CXXF) -o $@ ShowLibs.cpp
|
||||
|
||||
-include .deps-*
|
@ -1,73 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef linux
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
// A simple test program that dumps out the loaded shared
|
||||
// libraries. This is essential for leaky to work properly when shared
|
||||
// libraries are used.
|
||||
static void ShowLibs(struct r_debug* rd)
|
||||
{
|
||||
link_map* map = rd->r_map;
|
||||
while (NULL != map) {
|
||||
printf("addr=%08x name=%s prev=%p next=%p\n", map->l_addr, map->l_name,
|
||||
map->l_prev, map->l_next);
|
||||
map = map->l_next;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
void* h = dlopen("/usr/X11R6/lib/libX11.so", RTLD_LAZY);
|
||||
#ifdef linux
|
||||
printf("Direct r_debug libs:\n");
|
||||
ShowLibs(&_r_debug);
|
||||
|
||||
printf("_DYNAMICE r_debug libs:\n");
|
||||
ElfW(Dyn)* dp;
|
||||
for (dp = _DYNAMIC; dp->d_tag != DT_NULL; dp++) {
|
||||
if (dp->d_tag == DT_DEBUG) {
|
||||
struct r_debug* rd = (struct r_debug*) dp->d_un.d_ptr;
|
||||
ShowLibs(rd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
void s1(int, int)
|
||||
{
|
||||
malloc(100);
|
||||
}
|
||||
|
||||
void s2()
|
||||
{
|
||||
s1(1, 2);
|
||||
malloc(100);
|
||||
}
|
||||
|
||||
void s3()
|
||||
{
|
||||
s2();
|
||||
malloc(100);
|
||||
malloc(200);
|
||||
}
|
||||
|
||||
void s4()
|
||||
{
|
||||
s3();
|
||||
char* cp = new char[300];
|
||||
cp = cp;
|
||||
}
|
||||
|
||||
// Test that mutually recrusive methods don't foul up the graph output
|
||||
void s6(int recurse);
|
||||
|
||||
void s5(int recurse)
|
||||
{
|
||||
malloc(100);
|
||||
if (recurse > 0) {
|
||||
s6(recurse - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void s6(int recurse)
|
||||
{
|
||||
malloc(100);
|
||||
if (recurse > 0) {
|
||||
s5(recurse - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that two pathways through the same node don't cause replicated
|
||||
// descdendants (A -> B -> C, X -> B -> D shouldn't produce a graph
|
||||
// that shows A -> B -> D!)
|
||||
|
||||
void C()
|
||||
{
|
||||
malloc(10);
|
||||
}
|
||||
|
||||
void D()
|
||||
{
|
||||
malloc(10);
|
||||
}
|
||||
|
||||
void B(int way)
|
||||
{
|
||||
malloc(10);
|
||||
if (way) {
|
||||
C();
|
||||
C();
|
||||
C();
|
||||
} else {
|
||||
D();
|
||||
}
|
||||
}
|
||||
|
||||
void A()
|
||||
{
|
||||
malloc(10);
|
||||
B(1);
|
||||
}
|
||||
|
||||
void X()
|
||||
{
|
||||
malloc(10);
|
||||
B(0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
s1(1, 2);
|
||||
s2();
|
||||
s3();
|
||||
s4();
|
||||
s5(10);
|
||||
A();
|
||||
X();
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "TestPreload.h"
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// This is a simple test program that verifies that you can use
|
||||
// LD_PRELOAD to override the implementation of malloc for your
|
||||
// system. It depends on PreloadLib.cpp providing an alternate
|
||||
// implementation of malloc that has a special hack to return a
|
||||
// constant address given a particular size request.
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char* p = (char*) malloc(LD_PRELOAD_TEST_MALLOC_SIZE);
|
||||
if (p == (char*)LD_PRELOAD_TEST_VALUE) {
|
||||
printf("LD_PRELOAD worked - we are using our malloc\n");
|
||||
}
|
||||
else {
|
||||
printf("LD_PRELOAD failed\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#define LD_PRELOAD_TEST_MALLOC_SIZE 0x12345
|
||||
|
||||
#define LD_PRELOAD_TEST_VALUE 0x12345
|
@ -1,126 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "leaky.h"
|
||||
|
||||
#ifdef USE_BFD
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <bfd.h>
|
||||
|
||||
extern "C" {
|
||||
char *cplus_demangle (const char *mangled, int options);
|
||||
}
|
||||
|
||||
void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress)
|
||||
{
|
||||
static bfd_boolean kDynamic = (bfd_boolean) false;
|
||||
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
bfd_init ();
|
||||
}
|
||||
|
||||
bfd* lib = bfd_openr(aFileName, NULL);
|
||||
if (NULL == lib) {
|
||||
return;
|
||||
}
|
||||
char **matching;
|
||||
if (!bfd_check_format_matches(lib, bfd_object, &matching)) {
|
||||
bfd_close(lib);
|
||||
return;
|
||||
}
|
||||
|
||||
asymbol* store;
|
||||
store = bfd_make_empty_symbol(lib);
|
||||
|
||||
// read mini symbols
|
||||
PTR minisyms;
|
||||
unsigned int size;
|
||||
long symcount = bfd_read_minisymbols(lib, kDynamic, &minisyms, &size);
|
||||
|
||||
int initialSymbols = usefulSymbols;
|
||||
if (NULL == externalSymbols) {
|
||||
externalSymbols = (Symbol*) malloc(sizeof(Symbol) * 10000);
|
||||
numExternalSymbols = 10000;
|
||||
}
|
||||
Symbol* sp = externalSymbols + usefulSymbols;
|
||||
Symbol* lastSymbol = externalSymbols + numExternalSymbols;
|
||||
|
||||
// Scan symbols
|
||||
bfd_byte* from = (bfd_byte *) minisyms;
|
||||
bfd_byte* fromend = from + symcount * size;
|
||||
for (; from < fromend; from += size) {
|
||||
asymbol *sym;
|
||||
sym = bfd_minisymbol_to_symbol(lib, kDynamic, (const PTR) from, store);
|
||||
|
||||
symbol_info syminfo;
|
||||
bfd_get_symbol_info (lib, sym, &syminfo);
|
||||
|
||||
// if ((syminfo.type == 'T') || (syminfo.type == 't')) {
|
||||
const char* nm = bfd_asymbol_name(sym);
|
||||
if (nm && nm[0]) {
|
||||
char* dnm = NULL;
|
||||
if (strncmp("__thunk", nm, 7)) {
|
||||
dnm = cplus_demangle(nm, 1);
|
||||
}
|
||||
sp->Init(dnm ? dnm : nm, syminfo.value + aBaseAddress);
|
||||
sp++;
|
||||
if (sp >= lastSymbol) {
|
||||
long n = numExternalSymbols + 10000;
|
||||
externalSymbols = (Symbol*)
|
||||
realloc(externalSymbols, (size_t) (sizeof(Symbol) * n));
|
||||
lastSymbol = externalSymbols + n;
|
||||
sp = externalSymbols + numExternalSymbols;
|
||||
numExternalSymbols = n;
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
bfd_close(lib);
|
||||
|
||||
int interesting = sp - externalSymbols;
|
||||
if (!quiet) {
|
||||
printf("%s provided %d symbols\n", aFileName,
|
||||
interesting - initialSymbols);
|
||||
}
|
||||
usefulSymbols = interesting;
|
||||
}
|
||||
|
||||
#endif /* USE_BFD */
|
Binary file not shown.
Before Width: | Height: | Size: 88 B |
Binary file not shown.
Before Width: | Height: | Size: 88 B |
@ -1,130 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "leaky.h"
|
||||
|
||||
#ifdef USE_COFF
|
||||
|
||||
#define LANGUAGE_C
|
||||
#include <sym.h>
|
||||
#include <cmplrs/stsupport.h>
|
||||
#include <symconst.h>
|
||||
#include <filehdr.h>
|
||||
#include <ldfcn.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef IRIX4
|
||||
extern "C" {
|
||||
extern char *demangle(char const* in);
|
||||
};
|
||||
#else
|
||||
#include <dem.h>
|
||||
#endif
|
||||
|
||||
static char *Demangle(char *rawName)
|
||||
{
|
||||
#ifdef IRIX4
|
||||
return strdup(demangle(rawName));
|
||||
#else
|
||||
char namebuf[4000];
|
||||
demangle(rawName, namebuf);
|
||||
return strdup(namebuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void leaky::readSymbols(const char *fileName)
|
||||
{
|
||||
LDFILE *ldptr;
|
||||
|
||||
ldptr = ldopen(fileName, NULL);
|
||||
if (!ldptr) {
|
||||
fprintf(stderr, "%s: unable to open \"%s\"\n", applicationName,
|
||||
fileName);
|
||||
exit(-1);
|
||||
}
|
||||
if (PSYMTAB(ldptr) == 0) {
|
||||
fprintf(stderr, "%s: \"%s\": has no symbol table\n", applicationName,
|
||||
fileName);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
long isymMax = SYMHEADER(ldptr).isymMax;
|
||||
long iextMax = SYMHEADER(ldptr).iextMax;
|
||||
long iMax = isymMax + iextMax;
|
||||
|
||||
long alloced = 10000;
|
||||
Symbol* syms = (Symbol*) malloc(sizeof(Symbol) * 10000);
|
||||
Symbol* sp = syms;
|
||||
Symbol* last = syms + alloced;
|
||||
SYMR symr;
|
||||
|
||||
for (long isym = 0; isym < iMax; isym++) {
|
||||
if (ldtbread(ldptr, isym, &symr) != SUCCESS) {
|
||||
fprintf(stderr, "%s: can't read symbol #%d\n", applicationName,
|
||||
isym);
|
||||
exit(-1);
|
||||
}
|
||||
if (isym < isymMax) {
|
||||
if ((symr.st == stStaticProc)
|
||||
|| ((symr.st == stProc) &&
|
||||
((symr.sc == scText) || (symr.sc == scAbs)))
|
||||
|| ((symr.st == stBlock) &&
|
||||
(symr.sc == scText))) {
|
||||
// Text symbol. Set name field to point to the symbol name
|
||||
sp->name = Demangle(ldgetname(ldptr, &symr));
|
||||
sp->address = symr.value;
|
||||
sp++;
|
||||
if (sp >= last) {
|
||||
long n = alloced + 10000;
|
||||
syms = (Symbol*)
|
||||
realloc(syms, (size_t) (sizeof(Symbol) * n));
|
||||
last = syms + n;
|
||||
sp = syms + alloced;
|
||||
alloced = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int interesting = sp - syms;
|
||||
if (!quiet) {
|
||||
printf("Total of %d symbols\n", interesting);
|
||||
}
|
||||
usefulSymbols = interesting;
|
||||
externalSymbols = syms;
|
||||
}
|
||||
|
||||
#endif /* USE_COFF */
|
@ -1,60 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef config_h___
|
||||
#define config_h___
|
||||
|
||||
#define MAX_STACK_CRAWL 200
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#if defined(linux) || defined(NTO)
|
||||
#define USE_BFD
|
||||
#undef NEED_WRAPPERS
|
||||
|
||||
#define REAL_MALLOC(_x) __libc_malloc(_x)
|
||||
#define REAL_REALLOC(_x,_y) __libc_realloc(_x,_y)
|
||||
#define REAL_FREE(_x) __libc_free(_x)
|
||||
|
||||
extern "C" {
|
||||
void* __libc_malloc(size_t);
|
||||
void* __libc_realloc(void*, size_t);
|
||||
void __libc_free(void*);
|
||||
}
|
||||
|
||||
#endif /* linux */
|
||||
|
||||
#endif /* config_h___ */
|
@ -1,112 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kipp E.B. Hickman <kipp@netscape.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <malloc.h>
|
||||
#include "dict.h"
|
||||
|
||||
#ifdef __QNXNTO__
|
||||
/* Need definition of NULL */
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
MallocDict::MallocDict(int nb)
|
||||
{
|
||||
numBuckets = nb;
|
||||
buckets = (MallocDictEntry**) calloc(numBuckets, sizeof(MallocDictEntry*));
|
||||
rewind();
|
||||
}
|
||||
|
||||
void MallocDict::rewind(void)
|
||||
{
|
||||
iterNextBucket = -1;
|
||||
iterNextEntry = 0;
|
||||
}
|
||||
|
||||
malloc_log_entry* MallocDict::next(void)
|
||||
{
|
||||
if (iterNextEntry) {
|
||||
iterNextEntry = iterNextEntry->next;
|
||||
}
|
||||
while (!iterNextEntry) {
|
||||
iterNextBucket++;
|
||||
if (iterNextBucket >= numBuckets) {
|
||||
return 0;
|
||||
}
|
||||
iterNextEntry = buckets[iterNextBucket];
|
||||
}
|
||||
return iterNextEntry->logEntry;
|
||||
}
|
||||
|
||||
malloc_log_entry** MallocDict::find(u_long addr)
|
||||
{
|
||||
u_long hash = addr % numBuckets;
|
||||
MallocDictEntry* mde = buckets[hash];
|
||||
while (mde) {
|
||||
if (mde->addr == addr) {
|
||||
return &mde->logEntry;
|
||||
}
|
||||
mde = mde->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MallocDict::add(u_long addr, malloc_log_entry *lep)
|
||||
{
|
||||
u_long hash = addr % numBuckets;
|
||||
MallocDictEntry** mdep = &buckets[hash];
|
||||
MallocDictEntry* mde = new MallocDictEntry;
|
||||
mde->addr = addr;
|
||||
mde->logEntry = lep;
|
||||
mde->next = *mdep;
|
||||
*mdep = mde;
|
||||
}
|
||||
|
||||
void MallocDict::remove(u_long addr)
|
||||
{
|
||||
u_long hash = addr % numBuckets;
|
||||
MallocDictEntry** mdep = &buckets[hash];
|
||||
MallocDictEntry* mde;
|
||||
|
||||
while (NULL != (mde = *mdep)) {
|
||||
if (mde->addr == addr) {
|
||||
*mdep = mde->next;
|
||||
/*XXX delete mde; */
|
||||
return;
|
||||
}
|
||||
mdep = &mde->next;
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __dict_h_
|
||||
#define __dict_h_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "libmalloc.h"
|
||||
|
||||
// key is u_long
|
||||
// value is malloc_log_entry*
|
||||
struct MallocDict {
|
||||
MallocDict(int buckets);
|
||||
|
||||
void rewind(void);
|
||||
malloc_log_entry* next(void);
|
||||
|
||||
malloc_log_entry** find(u_long addr);
|
||||
void add(u_long addr, malloc_log_entry *log);
|
||||
void remove(u_long addr);
|
||||
|
||||
struct MallocDictEntry {
|
||||
u_long addr;
|
||||
malloc_log_entry* logEntry;
|
||||
MallocDictEntry* next;
|
||||
} **buckets;
|
||||
|
||||
int numBuckets;
|
||||
|
||||
int iterNextBucket;
|
||||
MallocDictEntry* iterNextEntry;
|
||||
};
|
||||
|
||||
#endif /* __dict_h_ */
|
@ -1,165 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "leaky.h"
|
||||
|
||||
#ifdef USE_ELF
|
||||
|
||||
#include "leaky.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <libelf/libelf.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
void leaky::readSymbols(const char *fileName)
|
||||
{
|
||||
int fd = ::open(fileName, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "%s: unable to open \"%s\"\n", applicationName,
|
||||
fileName);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
elf_version(EV_CURRENT);
|
||||
Elf *elf = elf_begin(fd, ELF_C_READ, 0);
|
||||
if (!elf) {
|
||||
fprintf(stderr, "%s: \"%s\": has no symbol table\n", applicationName,
|
||||
fileName);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
long alloced = 10000;
|
||||
Symbol* syms = (Symbol*) malloc(sizeof(Symbol) * 10000);
|
||||
Symbol* sp = syms;
|
||||
Symbol* last = syms + alloced;
|
||||
|
||||
// Get each of the relevant sections and add them to the list of
|
||||
// symbols.
|
||||
Elf32_Ehdr *ehdr = elf32_getehdr(elf);
|
||||
if (!ehdr) {
|
||||
fprintf(stderr, "%s: elf library lossage\n", applicationName);
|
||||
exit(-1);
|
||||
}
|
||||
#if 0
|
||||
Elf32_Half ndx = ehdr->e_shstrndx;
|
||||
#endif
|
||||
|
||||
Elf_Scn *scn = 0;
|
||||
int strtabndx = -1;
|
||||
for (int i = 1; (scn = elf_nextscn(elf, scn)) != 0; i++) {
|
||||
Elf32_Shdr *shdr = elf32_getshdr(scn);
|
||||
#if 0
|
||||
char *name = elf_strptr(elf, ndx, (size_t) shdr->sh_name);
|
||||
printf("Section %s (%d 0x%x)\n", name ? name : "(null)",
|
||||
shdr->sh_type, shdr->sh_type);
|
||||
#endif
|
||||
if (shdr->sh_type == SHT_STRTAB) {
|
||||
/* We assume here that string tables preceed symbol tables... */
|
||||
strtabndx = i;
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
if (shdr->sh_type == SHT_DYNAMIC) {
|
||||
/* Dynamic */
|
||||
Elf_Data *data = elf_getdata(scn, 0);
|
||||
if (!data || !data->d_size) {
|
||||
printf("No data...");
|
||||
continue;
|
||||
}
|
||||
|
||||
Elf32_Dyn *dyn = (Elf32_Dyn*) data->d_buf;
|
||||
Elf32_Dyn *lastdyn =
|
||||
(Elf32_Dyn*) ((char*) data->d_buf + data->d_size);
|
||||
for (; dyn < lastdyn; dyn++) {
|
||||
printf("tag=%d value=0x%x\n", dyn->d_tag, dyn->d_un.d_val);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if ((shdr->sh_type == SHT_SYMTAB) ||
|
||||
(shdr->sh_type == SHT_DYNSYM)) {
|
||||
/* Symbol table */
|
||||
Elf_Data *data = elf_getdata(scn, 0);
|
||||
if (!data || !data->d_size) {
|
||||
printf("No data...");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* In theory we now have the symbols... */
|
||||
Elf32_Sym *esym = (Elf32_Sym*) data->d_buf;
|
||||
Elf32_Sym *lastsym =
|
||||
(Elf32_Sym*) ((char*) data->d_buf + data->d_size);
|
||||
for (; esym < lastsym; esym++) {
|
||||
#if 0
|
||||
char *nm = elf_strptr(elf, strtabndx, (size_t)esym->st_name);
|
||||
printf("%20s 0x%08x %02x %02x\n",
|
||||
nm, esym->st_value, ELF32_ST_BIND(esym->st_info),
|
||||
ELF32_ST_TYPE(esym->st_info));
|
||||
#endif
|
||||
if ((esym->st_value == 0) ||
|
||||
(ELF32_ST_BIND(esym->st_info) == STB_WEAK) ||
|
||||
(ELF32_ST_BIND(esym->st_info) == STB_NUM) ||
|
||||
(ELF32_ST_TYPE(esym->st_info) != STT_FUNC)) {
|
||||
continue;
|
||||
}
|
||||
#if 1
|
||||
char *nm = elf_strptr(elf, strtabndx, (size_t)esym->st_name);
|
||||
#endif
|
||||
sp->name = nm ? strdup(nm) : "(no name)";
|
||||
sp->address = esym->st_value;
|
||||
sp++;
|
||||
if (sp >= last) {
|
||||
long n = alloced + 10000;
|
||||
syms = (Symbol*)
|
||||
realloc(syms, (size_t) (sizeof(Symbol) * n));
|
||||
last = syms + n;
|
||||
sp = syms + alloced;
|
||||
alloced = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int interesting = sp - syms;
|
||||
if (!quiet) {
|
||||
printf("Total of %d symbols\n", interesting);
|
||||
}
|
||||
usefulSymbols = interesting;
|
||||
externalSymbols = syms;
|
||||
}
|
||||
|
||||
#endif /* USE_ELF */
|
@ -1,784 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "leaky.h"
|
||||
#include "dict.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#ifndef NTO
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef NTO
|
||||
#include <mem.h>
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
static const u_int DefaultBuckets = 10007; // arbitrary, but prime
|
||||
static const u_int MaxBuckets = 1000003; // arbitrary, but prime
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
leaky* l = new leaky;
|
||||
|
||||
l->initialize(argc, argv);
|
||||
l->open();
|
||||
return 0;
|
||||
}
|
||||
|
||||
leaky::leaky()
|
||||
{
|
||||
applicationName = NULL;
|
||||
logFile = NULL;
|
||||
progFile = NULL;
|
||||
|
||||
dumpLeaks = FALSE;
|
||||
dumpGraph = FALSE;
|
||||
dumpHTML = FALSE;
|
||||
quiet = FALSE;
|
||||
dumpEntireLog = FALSE;
|
||||
showAddress = FALSE;
|
||||
stackDepth = 100000;
|
||||
dumpRefcnts = false;
|
||||
|
||||
mappedLogFile = -1;
|
||||
firstLogEntry = lastLogEntry = 0;
|
||||
buckets = DefaultBuckets;
|
||||
dict = NULL;
|
||||
refcntDict = NULL;
|
||||
|
||||
mallocs = 0;
|
||||
reallocs = 0;
|
||||
frees = 0;
|
||||
totalMalloced = 0;
|
||||
errors = 0;
|
||||
totalLeaked = 0;
|
||||
|
||||
sfd = -1;
|
||||
externalSymbols = 0;
|
||||
usefulSymbols = 0;
|
||||
numExternalSymbols = 0;
|
||||
lowestSymbolAddr = 0;
|
||||
highestSymbolAddr = 0;
|
||||
|
||||
loadMap = NULL;
|
||||
}
|
||||
|
||||
leaky::~leaky()
|
||||
{
|
||||
delete dict;
|
||||
}
|
||||
|
||||
void leaky::usageError()
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-aAEdfgqxR] [-e name] [-s depth] [-h hash-buckets] [-r root|-i symbol] prog log\n",
|
||||
(char*) applicationName);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void leaky::initialize(int argc, char** argv)
|
||||
{
|
||||
applicationName = argv[0];
|
||||
applicationName = strrchr(applicationName, '/');
|
||||
if (!applicationName) {
|
||||
applicationName = argv[0];
|
||||
} else {
|
||||
applicationName++;
|
||||
}
|
||||
|
||||
int arg;
|
||||
int errflg = 0;
|
||||
while ((arg = getopt(argc, argv, "adEe:gh:i:r:Rs:tqx")) != -1) {
|
||||
switch (arg) {
|
||||
case '?':
|
||||
errflg++;
|
||||
break;
|
||||
case 'a':
|
||||
dumpEntireLog = TRUE;
|
||||
break;
|
||||
case 'A':
|
||||
showAddress = TRUE;
|
||||
break;
|
||||
case 'd':
|
||||
dumpLeaks = TRUE;
|
||||
if (dumpGraph) errflg++;
|
||||
break;
|
||||
case 'R':
|
||||
dumpRefcnts = true;
|
||||
break;
|
||||
case 'e':
|
||||
exclusions.add(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
dumpGraph = TRUE;
|
||||
if (dumpLeaks) errflg++;
|
||||
break;
|
||||
case 'r':
|
||||
roots.add(optarg);
|
||||
if (!includes.IsEmpty()) {
|
||||
errflg++;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
includes.add(optarg);
|
||||
if (!roots.IsEmpty()) {
|
||||
errflg++;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
buckets = atoi(optarg);
|
||||
if ((buckets < 0) || (buckets > MaxBuckets)) {
|
||||
buckets = MaxBuckets;
|
||||
fprintf(stderr, "%s: buckets is invalid, using %d\n",
|
||||
(char*) applicationName,
|
||||
buckets);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
stackDepth = atoi(optarg);
|
||||
if (stackDepth < 2) {
|
||||
stackDepth = 2;
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
dumpHTML = TRUE;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errflg || ((argc - optind) < 2)) {
|
||||
usageError();
|
||||
}
|
||||
progFile = argv[optind++];
|
||||
logFile = argv[optind];
|
||||
|
||||
dict = new MallocDict(buckets);
|
||||
if (dumpRefcnts) {
|
||||
refcntDict = new MallocDict(buckets);
|
||||
}
|
||||
}
|
||||
|
||||
static void* mapFile(int fd, u_int flags, off_t* sz)
|
||||
{
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) < 0) {
|
||||
perror("fstat");
|
||||
exit(-1);
|
||||
}
|
||||
void* base = mmap(0, (int)sb.st_size, flags, MAP_PRIVATE, fd, 0);
|
||||
if (!base) {
|
||||
perror("mmap");
|
||||
exit(-1);
|
||||
}
|
||||
*sz = sb.st_size;
|
||||
return base;
|
||||
}
|
||||
|
||||
void leaky::LoadMap()
|
||||
{
|
||||
malloc_map_entry mme;
|
||||
char name[1000];
|
||||
|
||||
int fd = ::open("malloc-map", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open: malloc-map");
|
||||
exit(-1);
|
||||
}
|
||||
for (;;) {
|
||||
int nb = read(fd, &mme, sizeof(mme));
|
||||
if (nb != sizeof(mme)) break;
|
||||
nb = read(fd, name, mme.nameLen);
|
||||
if (nb != (int)mme.nameLen) break;
|
||||
name[mme.nameLen] = 0;
|
||||
if (!quiet) {
|
||||
printf("%s @ %lx\n", name, mme.address);
|
||||
}
|
||||
|
||||
LoadMapEntry* lme = new LoadMapEntry;
|
||||
lme->address = mme.address;
|
||||
lme->name = strdup(name);
|
||||
lme->next = loadMap;
|
||||
loadMap = lme;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void leaky::open()
|
||||
{
|
||||
LoadMap();
|
||||
|
||||
setupSymbols(progFile);
|
||||
|
||||
// open up the log file
|
||||
mappedLogFile = ::open(logFile, O_RDONLY);
|
||||
if (mappedLogFile < 0) {
|
||||
perror("open");
|
||||
exit(-1);
|
||||
}
|
||||
off_t size;
|
||||
firstLogEntry = (malloc_log_entry*) mapFile(mappedLogFile, PROT_READ, &size);
|
||||
lastLogEntry = (malloc_log_entry*)((char*)firstLogEntry + size);
|
||||
|
||||
analyze();
|
||||
|
||||
if (dumpLeaks || dumpEntireLog || dumpRefcnts) {
|
||||
dumpLog();
|
||||
}
|
||||
else if (dumpGraph) {
|
||||
buildLeakGraph();
|
||||
dumpLeakGraph();
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
static ptrdiff_t symbolOrder(void const* a, void const* b)
|
||||
{
|
||||
Symbol const* ap = (Symbol const *)a;
|
||||
Symbol const* bp = (Symbol const *)b;
|
||||
return ap->address - bp->address;
|
||||
}
|
||||
|
||||
void leaky::ReadSharedLibrarySymbols()
|
||||
{
|
||||
LoadMapEntry* lme = loadMap;
|
||||
while (NULL != lme) {
|
||||
ReadSymbols(lme->name, lme->address);
|
||||
lme = lme->next;
|
||||
}
|
||||
}
|
||||
|
||||
void leaky::setupSymbols(const char *fileName)
|
||||
{
|
||||
// Read in symbols from the program
|
||||
ReadSymbols(fileName, 0);
|
||||
|
||||
// Read in symbols from the .so's
|
||||
ReadSharedLibrarySymbols();
|
||||
|
||||
if (!quiet) {
|
||||
printf("A total of %d symbols were loaded\n", usefulSymbols);
|
||||
}
|
||||
|
||||
// Now sort them
|
||||
qsort(externalSymbols, usefulSymbols, sizeof(Symbol), symbolOrder);
|
||||
lowestSymbolAddr = externalSymbols[0].address;
|
||||
highestSymbolAddr = externalSymbols[usefulSymbols-1].address;
|
||||
}
|
||||
|
||||
// Binary search the table, looking for a symbol that covers this
|
||||
// address.
|
||||
Symbol* leaky::findSymbol(u_long addr)
|
||||
{
|
||||
u_int base = 0;
|
||||
u_int limit = usefulSymbols - 1;
|
||||
Symbol* end = &externalSymbols[limit];
|
||||
while (base <= limit) {
|
||||
u_int midPoint = (base + limit)>>1;
|
||||
Symbol* sp = &externalSymbols[midPoint];
|
||||
if (addr < sp->address) {
|
||||
if (midPoint == 0) {
|
||||
return NULL;
|
||||
}
|
||||
limit = midPoint - 1;
|
||||
} else {
|
||||
if (sp+1 < end) {
|
||||
if (addr < (sp+1)->address) {
|
||||
return sp;
|
||||
}
|
||||
} else {
|
||||
return sp;
|
||||
}
|
||||
base = midPoint + 1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool leaky::excluded(malloc_log_entry* lep)
|
||||
{
|
||||
if (exclusions.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char** pcp = &lep->pcs[0];
|
||||
u_int n = lep->numpcs;
|
||||
for (u_int i = 0; i < n; i++, pcp++) {
|
||||
Symbol* sp = findSymbol((u_long) *pcp);
|
||||
if (sp && exclusions.contains(sp->name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool leaky::included(malloc_log_entry* lep)
|
||||
{
|
||||
if (includes.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char** pcp = &lep->pcs[0];
|
||||
u_int n = lep->numpcs;
|
||||
for (u_int i = 0; i < n; i++, pcp++) {
|
||||
Symbol* sp = findSymbol((u_long) *pcp);
|
||||
if (sp && includes.contains(sp->name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void leaky::displayStackTrace(FILE* out, malloc_log_entry* lep)
|
||||
{
|
||||
char** pcp = &lep->pcs[0];
|
||||
u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth;
|
||||
for (u_int i = 0; i < n; i++, pcp++) {
|
||||
u_long addr = (u_long) *pcp;
|
||||
Symbol* sp = findSymbol(addr);
|
||||
if (sp) {
|
||||
fputs(sp->name, out);
|
||||
if (showAddress) {
|
||||
fprintf(out, "[%p]", (char*)addr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(out, "<%p>", (char*)addr);
|
||||
}
|
||||
fputc(' ', out);
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
char* typeFromLog[] = {
|
||||
"malloc",
|
||||
"realloc",
|
||||
"free",
|
||||
"new",
|
||||
"delete",
|
||||
"addref",
|
||||
"release"
|
||||
};
|
||||
|
||||
void leaky::dumpEntryToLog(malloc_log_entry* lep)
|
||||
{
|
||||
printf("%-10s %08lx %5ld ",
|
||||
typeFromLog[lep->type],
|
||||
lep->address, lep->size);
|
||||
if (IsRefcnt(lep)) {
|
||||
printf("%08ld", lep->oldaddress);
|
||||
}
|
||||
else {
|
||||
printf("%08lx", lep->oldaddress);
|
||||
}
|
||||
printf(" --> ");
|
||||
displayStackTrace(stdout, lep);
|
||||
}
|
||||
|
||||
bool leaky::ShowThisEntry(malloc_log_entry* lep)
|
||||
{
|
||||
if ((!dumpRefcnts || IsRefcnt(lep)) && !excluded(lep) && included(lep)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void leaky::dumpLog()
|
||||
{
|
||||
if (dumpRefcnts) {
|
||||
malloc_log_entry* lep;
|
||||
refcntDict->rewind();
|
||||
while (NULL != (lep = refcntDict->next())) {
|
||||
if (ShowThisEntry(lep)) {
|
||||
// Now we get slow...
|
||||
u_long addr = lep->address;
|
||||
malloc_log_entry* lep2 = firstLogEntry;
|
||||
while (lep2 < lastLogEntry) {
|
||||
if (lep2->address == addr) {
|
||||
dumpEntryToLog(lep2);
|
||||
}
|
||||
lep2 = (malloc_log_entry*) &lep2->pcs[lep2->numpcs];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dumpEntireLog) {
|
||||
malloc_log_entry* lep = firstLogEntry;
|
||||
while (lep < lastLogEntry) {
|
||||
if (ShowThisEntry(lep)) {
|
||||
dumpEntryToLog(lep);
|
||||
}
|
||||
lep = (malloc_log_entry*) &lep->pcs[lep->numpcs];
|
||||
}
|
||||
} else {
|
||||
malloc_log_entry* lep;
|
||||
dict->rewind();
|
||||
while (NULL != (lep = dict->next())) {
|
||||
if (ShowThisEntry(lep)) {
|
||||
dumpEntryToLog(lep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void leaky::insertAddress(u_long address, malloc_log_entry* lep)
|
||||
{
|
||||
malloc_log_entry** lepp = dict->find(address);
|
||||
if (lepp) {
|
||||
assert(*lepp);
|
||||
if (!quiet) {
|
||||
printf("Address %lx allocated twice\n", address);
|
||||
displayStackTrace(stdout, lep);
|
||||
}
|
||||
errors++;
|
||||
} else {
|
||||
dict->add(address, lep);
|
||||
}
|
||||
}
|
||||
|
||||
void leaky::removeAddress(u_long address, malloc_log_entry* lep)
|
||||
{
|
||||
malloc_log_entry** lepp = dict->find(address);
|
||||
if (!lepp) {
|
||||
if (!quiet) {
|
||||
printf("Free of unallocated %lx\n", address);
|
||||
displayStackTrace(stdout, lep);
|
||||
}
|
||||
errors++;
|
||||
} else {
|
||||
dict->remove(address);
|
||||
}
|
||||
}
|
||||
|
||||
void leaky::analyze()
|
||||
{
|
||||
malloc_log_entry* lep = firstLogEntry;
|
||||
while (lep < lastLogEntry) {
|
||||
switch (lep->type) {
|
||||
case malloc_log_malloc:
|
||||
case malloc_log_new:
|
||||
mallocs++;
|
||||
if (lep->address) {
|
||||
totalMalloced += lep->size;
|
||||
insertAddress((u_long) lep->address, lep);
|
||||
}
|
||||
break;
|
||||
|
||||
case malloc_log_realloc:
|
||||
if (lep->oldaddress) {
|
||||
removeAddress((u_long) lep->oldaddress, lep);
|
||||
}
|
||||
if (lep->address) {
|
||||
insertAddress((u_long) lep->address, lep);
|
||||
}
|
||||
reallocs++;
|
||||
break;
|
||||
|
||||
case malloc_log_free:
|
||||
case malloc_log_delete:
|
||||
if (lep->address) {
|
||||
removeAddress((u_long) lep->address, lep);
|
||||
}
|
||||
frees++;
|
||||
break;
|
||||
case malloc_log_addref:
|
||||
if (dumpRefcnts) {
|
||||
if (lep->size == 0) {
|
||||
// Initial addref
|
||||
u_long addr = (u_long) lep->address;
|
||||
malloc_log_entry** lepp = refcntDict->find(addr);
|
||||
if (!lepp) {
|
||||
refcntDict->add(addr, lep);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case malloc_log_release:
|
||||
if (dumpRefcnts) {
|
||||
if (lep->oldaddress == 0) {
|
||||
// Final release
|
||||
u_long addr = (u_long) lep->address;
|
||||
malloc_log_entry** lepp = refcntDict->find(addr);
|
||||
if (lepp) {
|
||||
refcntDict->remove(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
lep = (malloc_log_entry*) &lep->pcs[lep->numpcs];
|
||||
}
|
||||
|
||||
dict->rewind();
|
||||
while (NULL != (lep = dict->next())) {
|
||||
totalLeaked += lep->size;
|
||||
}
|
||||
|
||||
if (!quiet) {
|
||||
printf("# of mallocs = %ld\n", mallocs);
|
||||
printf("# of reallocs = %ld\n", reallocs);
|
||||
printf("# of frees = %ld\n", frees);
|
||||
printf("# of errors = %ld\n", errors);
|
||||
printf("Total bytes allocated = %ld\n", totalMalloced);
|
||||
printf("Total bytes leaked = %ld\n", totalLeaked);
|
||||
printf("Average bytes per malloc = %g\n",
|
||||
float(totalMalloced)/mallocs);
|
||||
}
|
||||
}
|
||||
|
||||
void leaky::buildLeakGraph()
|
||||
{
|
||||
// For each leak
|
||||
malloc_log_entry* lep;
|
||||
dict->rewind();
|
||||
while (NULL != (lep = dict->next())) {
|
||||
if (ShowThisEntry(lep)) {
|
||||
char** basepcp = &lep->pcs[0];
|
||||
char** pcp = &lep->pcs[lep->numpcs - 1];
|
||||
|
||||
// Find root for this allocation
|
||||
Symbol* sym = findSymbol((u_long) *pcp);
|
||||
TreeNode* node = sym->root;
|
||||
if (!node) {
|
||||
sym->root = node = new TreeNode(sym);
|
||||
|
||||
// Add root to list of roots
|
||||
if (roots.IsEmpty()) {
|
||||
node->nextRoot = rootList;
|
||||
rootList = node;
|
||||
}
|
||||
}
|
||||
pcp--;
|
||||
|
||||
// Build tree underneath the root
|
||||
for (; pcp >= basepcp; pcp--) {
|
||||
// Share nodes in the tree until there is a divergence
|
||||
sym = findSymbol((u_long) *pcp);
|
||||
if (!sym) {
|
||||
break;
|
||||
}
|
||||
TreeNode* nextNode = node->GetDirectDescendant(sym);
|
||||
if (!nextNode) {
|
||||
// Make a new node at the point of divergence
|
||||
nextNode = node->AddDescendant(sym);
|
||||
}
|
||||
|
||||
// See if the symbol is to be a user specified root. If it is,
|
||||
// and we haven't already stuck it on the root-list do so now.
|
||||
if (!sym->root && !roots.IsEmpty() && roots.contains(sym->name)) {
|
||||
sym->root = nextNode;
|
||||
nextNode->nextRoot = rootList;
|
||||
rootList = nextNode;
|
||||
}
|
||||
|
||||
if (pcp == basepcp) {
|
||||
nextNode->bytesLeaked += lep->size;
|
||||
}
|
||||
else {
|
||||
node->descendantBytesLeaked += lep->size;
|
||||
}
|
||||
|
||||
node = nextNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Symbol* leaky::findLeakGraphRoot(Symbol* aStart, Symbol* aEnd)
|
||||
{
|
||||
while (aStart < aEnd) {
|
||||
if (aStart->root) {
|
||||
return aStart;
|
||||
}
|
||||
aStart++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void leaky::dumpLeakGraph()
|
||||
{
|
||||
if (dumpHTML) {
|
||||
printf("<html><head><title>Leaky Graph</title>\n");
|
||||
printf("<style src=\"resource:/res/leaky/leaky.css\"></style>\n");
|
||||
printf("<script src=\"resource:/res/leaky/leaky.js\"></script>\n");
|
||||
printf("</head><body><div class=\"key\">\n");
|
||||
printf("Key:<br>\n");
|
||||
printf("<span class=b>Bytes directly leaked</span><br>\n");
|
||||
printf("<span class=d>Bytes leaked by descendants</span></div>\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
Symbol* base = externalSymbols;
|
||||
Symbol* end = externalSymbols + usefulSymbols;
|
||||
while (base < end) {
|
||||
Symbol* sym = findLeakGraphRoot(base, end);
|
||||
if (!sym) break;
|
||||
dumpLeakTree(sym->root, 0);
|
||||
base = sym + 1;
|
||||
}
|
||||
#else
|
||||
TreeNode* root = rootList;
|
||||
while (root) {
|
||||
dumpLeakTree(root, 0);
|
||||
root = root->nextRoot;
|
||||
}
|
||||
#endif
|
||||
if (dumpHTML) {
|
||||
printf("</body></html>\n");
|
||||
}
|
||||
}
|
||||
|
||||
void leaky::dumpLeakTree(TreeNode* aNode, int aIndent)
|
||||
{
|
||||
Symbol* sym = aNode->symbol;
|
||||
if (dumpHTML) {
|
||||
printf("<div class=\"n\">\n");
|
||||
if (aNode->HasDescendants()) {
|
||||
printf("<img onmouseout=\"O(event);\" onmouseover=\"I(event);\" ");
|
||||
printf("onclick=\"C(event);\" src=\"resource:/res/leaky/%s.gif\">",
|
||||
aIndent > 1 ? "close" : "open");
|
||||
}
|
||||
printf("<span class=s>%s</span><span class=b>%ld</span>",
|
||||
sym->name,
|
||||
aNode->bytesLeaked);
|
||||
printf("<span class=d>%ld</span>\n",
|
||||
aNode->descendantBytesLeaked);
|
||||
}
|
||||
else {
|
||||
indentBy(aIndent);
|
||||
printf("%s bytesLeaked=%ld (%ld from kids)\n",
|
||||
sym->name,
|
||||
aNode->bytesLeaked,
|
||||
aNode->descendantBytesLeaked);
|
||||
}
|
||||
|
||||
TreeNode* node = aNode->descendants;
|
||||
int kidNum = 0;
|
||||
while (node) {
|
||||
sym = node->symbol;
|
||||
dumpLeakTree(node, aIndent + 1);
|
||||
kidNum++;
|
||||
node = node->nextSibling;
|
||||
}
|
||||
|
||||
if (dumpHTML) {
|
||||
printf("</div>");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
TreeNode* TreeNode::freeList;
|
||||
|
||||
void* TreeNode::operator new(size_t size) CPP_THROW_NEW
|
||||
{
|
||||
if (!freeList) {
|
||||
TreeNode* newNodes = (TreeNode*) new char[sizeof(TreeNode) * 5000];
|
||||
if (!newNodes) {
|
||||
return NULL;
|
||||
}
|
||||
TreeNode* n = newNodes;
|
||||
TreeNode* end = newNodes + 5000 - 1;
|
||||
while (n < end) {
|
||||
n->nextSibling = n + 1;
|
||||
n++;
|
||||
}
|
||||
n->nextSibling = NULL;
|
||||
freeList = newNodes;
|
||||
}
|
||||
|
||||
TreeNode* rv = freeList;
|
||||
freeList = rv->nextSibling;
|
||||
|
||||
return (void*) rv;
|
||||
}
|
||||
|
||||
void TreeNode::operator delete(void* ptr)
|
||||
{
|
||||
TreeNode* node = (TreeNode*) ptr;
|
||||
if (node) {
|
||||
node->nextSibling = freeList;
|
||||
freeList = node;
|
||||
}
|
||||
}
|
||||
|
||||
TreeNode* TreeNode::GetDirectDescendant(Symbol* aSymbol)
|
||||
{
|
||||
TreeNode* node = descendants;
|
||||
while (node) {
|
||||
if (node->symbol == aSymbol) {
|
||||
return node;
|
||||
}
|
||||
node = node->nextSibling;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TreeNode* TreeNode::AddDescendant(Symbol* aSymbol)
|
||||
{
|
||||
TreeNode* node = new TreeNode(aSymbol);
|
||||
node->nextSibling = descendants;
|
||||
descendants = node;
|
||||
return node;
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
body {
|
||||
background-color: white;
|
||||
line-height: 1.1;
|
||||
margin: 1em;
|
||||
font-size: 10pt;
|
||||
font-family: "Arial", "Times New Roman", "Times Roman", serif;
|
||||
}
|
||||
|
||||
body > .n, body > .n > .n, body > .n > .n > .n {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.key {
|
||||
display: block;
|
||||
margin: 1em;
|
||||
border: 2px solid green;
|
||||
width: 50%;
|
||||
margin: 0 auto 1em auto;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
.key .b, .key .d {
|
||||
margin: 0 0 0 2em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.n {
|
||||
display: none;
|
||||
margin: 0 0 0 1em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.n.e {
|
||||
background-color: rgb(180,180,180);
|
||||
}
|
||||
|
||||
.s {
|
||||
display: inline;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.b {
|
||||
display: inline;
|
||||
background-color: yellow;
|
||||
margin: 0 1em 0 1em;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.d {
|
||||
display: inline;
|
||||
background-color: khaki;
|
||||
padding: 0 5px;
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __leaky_h_
|
||||
#define __leaky_h_
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include "dict.h"
|
||||
#include "strset.h"
|
||||
#include "xpcom-config.h" // for CPP_NEW_THROW
|
||||
|
||||
typedef unsigned int u_int;
|
||||
|
||||
struct Symbol;
|
||||
|
||||
struct TreeNode {
|
||||
TreeNode(Symbol* aSymbol) {
|
||||
symbol = aSymbol;
|
||||
nextSibling = NULL;
|
||||
descendants = NULL;
|
||||
nextRoot = NULL;
|
||||
bytesLeaked = 0;
|
||||
descendantBytesLeaked = 0;
|
||||
}
|
||||
|
||||
TreeNode* GetDirectDescendant(Symbol* aSymbol);
|
||||
|
||||
bool HasDescendants() const {
|
||||
return NULL != descendants;
|
||||
}
|
||||
|
||||
TreeNode* AddDescendant(Symbol* aSymbol);
|
||||
|
||||
TreeNode* descendants;
|
||||
TreeNode* nextSibling;
|
||||
TreeNode* nextRoot;
|
||||
Symbol* symbol;
|
||||
|
||||
u_long bytesLeaked;
|
||||
u_long descendantBytesLeaked;
|
||||
|
||||
void* operator new(size_t size) CPP_THROW_NEW ;
|
||||
void operator delete(void* ptr);
|
||||
|
||||
static TreeNode* freeList;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
char* name;
|
||||
u_long address;
|
||||
TreeNode* root;
|
||||
|
||||
void Init(const char* aName, u_long aAddress) {
|
||||
name = aName ? strdup(aName) : (char *)"";
|
||||
address = aAddress;
|
||||
root = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct LoadMapEntry {
|
||||
char* name; // name of .so
|
||||
u_long address; // base address where it was mapped in
|
||||
LoadMapEntry* next;
|
||||
};
|
||||
|
||||
struct leaky {
|
||||
leaky();
|
||||
~leaky();
|
||||
|
||||
void initialize(int argc, char** argv);
|
||||
void open();
|
||||
|
||||
char* applicationName;
|
||||
char* logFile;
|
||||
char* progFile;
|
||||
|
||||
int dumpLeaks;
|
||||
int dumpGraph;
|
||||
int dumpHTML;
|
||||
int quiet;
|
||||
int dumpEntireLog;
|
||||
int showAddress;
|
||||
bool dumpRefcnts;
|
||||
u_int stackDepth;
|
||||
|
||||
int mappedLogFile;
|
||||
malloc_log_entry* firstLogEntry;
|
||||
malloc_log_entry* lastLogEntry;
|
||||
u_int buckets;
|
||||
MallocDict* dict;
|
||||
MallocDict* refcntDict;
|
||||
|
||||
u_long mallocs;
|
||||
u_long reallocs;
|
||||
u_long frees;
|
||||
u_long totalMalloced;
|
||||
u_long errors;
|
||||
u_long totalLeaked;
|
||||
|
||||
int sfd;
|
||||
Symbol* externalSymbols;
|
||||
u_int usefulSymbols;
|
||||
u_int numExternalSymbols;
|
||||
StrSet exclusions;
|
||||
u_long lowestSymbolAddr;
|
||||
u_long highestSymbolAddr;
|
||||
|
||||
LoadMapEntry* loadMap;
|
||||
|
||||
TreeNode* rootList;
|
||||
|
||||
StrSet roots;
|
||||
StrSet includes;
|
||||
|
||||
void usageError();
|
||||
|
||||
void LoadMap();
|
||||
|
||||
void analyze();
|
||||
|
||||
void dumpLog();
|
||||
void dumpEntryToLog(malloc_log_entry* lep);
|
||||
|
||||
#if 0
|
||||
void dumpToTree();
|
||||
void dumpEntryToTree(FILE* fp, malloc_log_entry* lep);
|
||||
#endif
|
||||
|
||||
void insertAddress(u_long address, malloc_log_entry* lep);
|
||||
void removeAddress(u_long address, malloc_log_entry* lep);
|
||||
|
||||
void displayStackTrace(FILE* out, malloc_log_entry* lep);
|
||||
|
||||
void ReadSymbols(const char* fileName, u_long aBaseAddress);
|
||||
void ReadSharedLibrarySymbols();
|
||||
void setupSymbols(const char* fileName);
|
||||
Symbol* findSymbol(u_long address);
|
||||
bool excluded(malloc_log_entry* lep);
|
||||
bool included(malloc_log_entry* lep);
|
||||
|
||||
void buildLeakGraph();
|
||||
Symbol* findLeakGraphRoot(Symbol* aStart, Symbol* aEnd);
|
||||
void dumpLeakGraph();
|
||||
void dumpLeakTree(TreeNode* aNode, int aIndent);
|
||||
|
||||
bool ShowThisEntry(malloc_log_entry* lep);
|
||||
|
||||
bool IsRefcnt(malloc_log_entry* lep) const {
|
||||
return (lep->type == malloc_log_addref) ||
|
||||
(lep->type == malloc_log_release);
|
||||
}
|
||||
|
||||
static void indentBy(int aCount) {
|
||||
while (--aCount >= 0) fputs(" ", stdout);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __leaky_h_ */
|
@ -1,224 +0,0 @@
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.61 [en] (X11; I; Linux 2.2.5-22 i686) [Netscape]">
|
||||
<title>Leaky</title>
|
||||
</head>
|
||||
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B" alink="#FF0000">
|
||||
|
||||
<center><b><font face="Arial,Helvetica"><font size=+2>Leaky</font></font></b></center>
|
||||
|
||||
<p>Leaky is a program which will help you find memory leaks, and as of
|
||||
late, help you debug reference count problems with xpcom objects.
|
||||
<p><b><font face="Arial,Helvetica"><font size=+2>Get the Source</font></font></b>
|
||||
<p>Leaky is not currently part of the default SeaMonkey module,
|
||||
<br>you will need to explicitly pull the source:
|
||||
<br>
|
||||
<pre> cvs checkout mozilla/tools/leaky</pre>
|
||||
If there is enough demand, we can make this part of the default SeaMonkey
|
||||
module.
|
||||
<p><b><font face="Arial,Helvetica"><font size=+2>Building it</font></font></b>
|
||||
<br>
|
||||
<pre> ./configure --enable-leaky</pre>
|
||||
Top-of-tree build should Just Build It and leaky will show up in dist/bin.
|
||||
<p><b><font face="Arial,Helvetica"><font size=+2>Using Leaky</font></font></b>
|
||||
<p>After it has been built, you can use TestPreload and TestMalloc and
|
||||
ShowLibs to debug your implementation.
|
||||
<p>By setting the <tt>LIBMALLOC_LOG</tt> environment variable you control
|
||||
how much information is logged during the programs execution. See libmalloc.h
|
||||
for a definition of the values to use. If you are using <tt>LD_PRELOAD</tt>,
|
||||
here is one way to run your program:
|
||||
<blockquote><tt>env LD_PRELOAD=/full/path/to/libleaky.so LIBMALLOC_LOG=1
|
||||
my-program</tt></blockquote>
|
||||
The debugging malloc library creates two files, <tt>malloc-log</tt> and
|
||||
<tt>malloc-map</tt>.
|
||||
The malloc-log file can be quite large for large programs (e.g. mozilla)
|
||||
so be prepared to have a lot of disk space. The malloc-map is tiny.
|
||||
<p>Once your program has completed execution you can use leaky to look
|
||||
for memory leaks, or at least use it to dump the log. For memory leaks,
|
||||
you use leaky like this:
|
||||
<blockquote><tt>leaky -d <program-name-goes-here> malloc-log</tt></blockquote>
|
||||
Leaky will then display all of the call sites where memory was leaked.
|
||||
To look at the entire log file contents, not just the leaks add "-a" to
|
||||
the arguments:
|
||||
<blockquote><tt>leaky -d -a <program-name-goes-here> malloc-log</tt></blockquote>
|
||||
For debugging reference count issues, here is what I do:
|
||||
<ol>
|
||||
<li>
|
||||
Set LIBMALLOC_LOG to "8"</li>
|
||||
|
||||
<li>
|
||||
Modify your source code so that your class::Addref and class::Release methods
|
||||
call __log_addref and __log_release, as appropriate. See libmalloc.h for
|
||||
their signatures. If you are using mozilla, you no longer need to modify
|
||||
your source code with a debug build. See
|
||||
<a href="http://lxr.mozilla.org/seamonkey/source/xpcom/doc/MemoryTools.html">
|
||||
xpcom/doc/MemoryTools.html</a> for more info.
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Run your program so that you get the log data. Its often convenient to
|
||||
run your program in the debugger and then set a breakpoint at an interesting
|
||||
location where you think some object is being leaked or over-freed. Then
|
||||
when the debugger gets there tell it to execute DumpAddressMap. In gdb
|
||||
you do this:</li>
|
||||
|
||||
<ol>
|
||||
<br><tt>(gdb) p DumpAddressMap()</tt></ol>
|
||||
|
||||
<li>
|
||||
Then use leaky to capture the addref and release calls to a log file:</li>
|
||||
|
||||
<ol>
|
||||
<br><tt>leaky -d -a <program-name-goes-here> malloc-log > log</tt></ol>
|
||||
|
||||
<li>
|
||||
Then use "grep" to search the log for a specific object by grepping for
|
||||
its memory address...</li>
|
||||
|
||||
<li>
|
||||
On a typical *short* run of mozilla, I'll end up with a malloc-log file
|
||||
of around 5 to 10 megabytes and the resulting converted log file will be
|
||||
10 to 20 times that so be prepared to have a lot of disk space. It helps
|
||||
a great deal to narrow down your problem space to reduce the log file size...</li>
|
||||
</ol>
|
||||
|
||||
<p><br>Leaky now has a "graph" output option. If you do this:
|
||||
<pre> leaky -gqx <program-name-goes-here> malloc-log | sed -e 's/&/&/g' > /tmp/GQ0.html</pre>
|
||||
Then leaky will make a graph of the leaks [-g] and output that graph in
|
||||
xml format (currently actually html...) [-x]. I use sed to make it legitimate
|
||||
html and off it goes to a file.
|
||||
<p>If you throw file at viewer (recursion is cool) then it will present
|
||||
you with a treeview of the leaks that you can click on to open/close sections.
|
||||
Enjoy!
|
||||
<p><b><font face="Arial,Helvetica"><font size=+2>Command Line Options</font></font></b>
|
||||
<br>
|
||||
<table CELLSPACING=5 CELLPADDING=0 WIDTH="100%" NOSAVE >
|
||||
<tr>
|
||||
<td>-a</td>
|
||||
|
||||
<td>dump the entire log. This means all malloc's, free's, new's, delete's,
|
||||
addref's or release's will be displayed</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-d</td>
|
||||
|
||||
<td>dump leaks (only one of -d, -R or -g can be used at a time)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-R</td>
|
||||
|
||||
<td>dump refcnts</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> </td>
|
||||
|
||||
<td> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-g</td>
|
||||
|
||||
<td>display a graph of leaks</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-x</td>
|
||||
|
||||
<td>when displaying the graph with -g, use html output that can be fed
|
||||
into an html4+css+dom compliant viewer (like mozilla :-)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-r symbol</td>
|
||||
|
||||
<td>define a root for the graph dump. nodes in the graph above symbol will
|
||||
be hidden, thus reducing the depth of the graph making it easier to find
|
||||
deeper leaks.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> </td>
|
||||
|
||||
<td> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-e symbol</td>
|
||||
|
||||
<td>exclude leaks that include symbol from treatment</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-i symbol</td>
|
||||
|
||||
<td>include leaks that include symbol for treatment. If an includes are
|
||||
defined than only leaks which include the symbols will be processed. excludes
|
||||
will still apply to this reduced set of leaks</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> </td>
|
||||
|
||||
<td> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-A</td>
|
||||
|
||||
<td>show the address in the stack crawls, not just the symobls</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-h num</td>
|
||||
|
||||
<td>set the size of the hash buckets used by leaksy dictionaries to <num></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-s depth</td>
|
||||
|
||||
<td>set the depth of the stack crawls shown when displaying stack crawls
|
||||
(any of the dumping modes except -g)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-q</td>
|
||||
|
||||
<td>make leaky quiet (don't dump the information about symbols being read
|
||||
and from which libraries)</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p><b><font face="Arial,Helvetica"><font size=+2>Porting to non-Intel/Linux</font></font></b>
|
||||
<br>
|
||||
<p>Initial version works only on x86 linux. To work on other platforms
|
||||
you will need to:
|
||||
<ol>
|
||||
<li>
|
||||
Implement <tt>CrawlStack()</tt> in libmalloc.cpp</li>
|
||||
|
||||
<li>
|
||||
Implement <tt>DumpAddressMap()</tt> in libmalloc.cpp and in ShowLibs.cpp</li>
|
||||
|
||||
<li>
|
||||
Either support LD_PRELOAD in your dynamic linker, <b>or</b></li>
|
||||
|
||||
<br>produce a library that wraps your libc malloc (see config.h for some
|
||||
clues)
|
||||
<li>
|
||||
Implement symbol table reading code (see coff.cpp, elf.cpp and bfd.cpp
|
||||
for examples; at the time of writing this document only bfd.cpp was known
|
||||
to work)</li>
|
||||
</ol>
|
||||
|
||||
<hr><!-- hhmts start -->Last modified: Sun Sep 26 13:15:33 PDT 1999<!-- hhmts end -->
|
||||
<br>Send comments to <i><a href="mailto:kipp@netscape.com">Kipp Hickman</a></i>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
@ -1,39 +0,0 @@
|
||||
var lastIn;
|
||||
function I(event) {
|
||||
var it = event.target;
|
||||
if (it) {
|
||||
var s = it.src;
|
||||
s = s.replace("-over", ""); // just in case
|
||||
s = s.replace(".gif", "-over.gif");
|
||||
it.src = s;
|
||||
lastIn = it;
|
||||
}
|
||||
}
|
||||
function O(event) {
|
||||
var it = lastIn;
|
||||
if (it) {
|
||||
var s = it.src;
|
||||
s = s.replace("-over", "");
|
||||
it.src = s;
|
||||
lastIn = null;
|
||||
}
|
||||
}
|
||||
function C(event) {
|
||||
var it = event.target;
|
||||
if (!it) return;
|
||||
var kids = it.parentNode.childNodes;
|
||||
if (!kids) return;
|
||||
for (var i = 0; i < kids.length; i++) {
|
||||
var kid = kids[i];
|
||||
if ((kid.nodeType == Node.ELEMENT_NODE) && (kid.tagName == "DIV")) {
|
||||
var d = kid.style.display;
|
||||
if ((d == "") || (d == null) || (d == "none")) {
|
||||
it.src = it.src.replace("close", "open");
|
||||
kid.style.display = "block";
|
||||
} else {
|
||||
kid.style.display = "none";
|
||||
it.src = it.src.replace("open", "close");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,608 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "libmalloc.h"
|
||||
#include <memory.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef NTO
|
||||
#include <sys/link.h>
|
||||
extern r_debug _r_debug;
|
||||
#else
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
#ifdef NTO
|
||||
#define JB_BP 0x08
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#ifdef NEED_WRAPPERS
|
||||
void* __wrap_malloc(size_t);
|
||||
void* __wrap_realloc(void*, size_t);
|
||||
void __wrap_free(void*);
|
||||
void* __wrap___builtin_new(size_t);
|
||||
void __wrap___builtin_delete(void*);
|
||||
void* __wrap___builtin_vec_new(size_t);
|
||||
void __wrap___builtin_vec_delete(void*);
|
||||
void* __wrap_PR_Malloc(size_t);
|
||||
void* __wrap_PR_Calloc(size_t, size_t);
|
||||
void* __wrap_PR_Realloc(void*, size_t);
|
||||
void __wrap_PR_Free(void*);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int gLogFD = -1;
|
||||
static u_long gFlags;
|
||||
static int gFillCount = 0;
|
||||
|
||||
#define MARKER0 0xFFFFFFFF
|
||||
#define MARKER1 0xEEEEEEEE
|
||||
#define MARKER2_0 0xD8D8D8D8
|
||||
#define MARKER2_1 0xE8E8E8E8
|
||||
|
||||
#define PATTERN_BYTE 0xFE
|
||||
#define FREE_PATTERN_BYTE 0xDE
|
||||
|
||||
struct Header {
|
||||
u_long marker0;
|
||||
size_t rawSize; // user requested size
|
||||
size_t size; // size rounded up
|
||||
u_long marker1;
|
||||
};
|
||||
|
||||
struct Trailer {
|
||||
u_long marker2[2];
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#if defined(i386)
|
||||
static void CrawlStack(malloc_log_entry* me, jmp_buf jb)
|
||||
{
|
||||
#ifdef NTO
|
||||
u_long* bp = (u_long*) (jb[0].__savearea[JB_BP]);
|
||||
#else
|
||||
u_long* bp = (u_long*) (jb[0].__jmpbuf[JB_BP]);
|
||||
#endif
|
||||
u_long numpcs = 0;
|
||||
int skip = 2;
|
||||
while (numpcs < MAX_STACK_CRAWL) {
|
||||
u_long* nextbp = (u_long*) *bp++;
|
||||
u_long pc = *bp;
|
||||
if ((pc < 0x08000000) || (pc > 0x7fffffff) || (nextbp < bp)) {
|
||||
break;
|
||||
}
|
||||
if (--skip < 0) {
|
||||
me->pcs[numpcs++] = (char*) pc;
|
||||
}
|
||||
bp = nextbp;
|
||||
}
|
||||
me->numpcs = numpcs;
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#if defined(linux) || defined(NTO)
|
||||
static void DumpAddressMap()
|
||||
{
|
||||
int mfd = open("malloc-map", O_CREAT|O_WRONLY|O_TRUNC, 0666);
|
||||
if (mfd >= 0) {
|
||||
malloc_map_entry mme;
|
||||
link_map* map = _r_debug.r_map;
|
||||
while (NULL != map) {
|
||||
if (0 != map->l_addr) {
|
||||
mme.nameLen = strlen(map->l_name);
|
||||
mme.address = map->l_addr;
|
||||
write(mfd, &mme, sizeof(mme));
|
||||
write(mfd, map->l_name, mme.nameLen);
|
||||
#if 0
|
||||
write(1, map->l_name, mme.nameLen);
|
||||
write(1, "\n", 1);
|
||||
#endif
|
||||
}
|
||||
map = map->l_next;
|
||||
}
|
||||
close(mfd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static int Verify(Header* h)
|
||||
{
|
||||
// Sanity check the header first
|
||||
if ((h->marker0 != MARKER0) ||
|
||||
(h->marker1 != MARKER1) ||
|
||||
(h->rawSize > h->size)) {
|
||||
DumpAddressMap();
|
||||
abort();
|
||||
}
|
||||
|
||||
// Sanity check the trailer second
|
||||
Trailer* t = (Trailer*) ((char*)(h + 1) + h->size);
|
||||
if ((t->marker2[0] != MARKER2_0) ||
|
||||
(t->marker2[1] != MARKER2_1)) {
|
||||
DumpAddressMap();
|
||||
abort();
|
||||
}
|
||||
|
||||
// Verify there were no overruns
|
||||
size_t fill = h->size - h->rawSize;
|
||||
if (0 != fill) {
|
||||
unsigned char* cp = ((unsigned char*)(h + 1)) + h->rawSize;
|
||||
unsigned char* end = cp + fill;
|
||||
while (cp < end) {
|
||||
unsigned char ch = *cp++;
|
||||
if (ch != PATTERN_BYTE) {
|
||||
DumpAddressMap();
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
Log(int aType, void* aAddr, size_t aSize, void* aOldAddr)
|
||||
{
|
||||
malloc_log_entry me;
|
||||
|
||||
me.type = (u_long) aType;
|
||||
me.address = (u_long) aAddr;
|
||||
me.size = (u_long) aSize;
|
||||
me.oldaddress = (u_long) aOldAddr;
|
||||
|
||||
jmp_buf jb;
|
||||
setjmp(jb);
|
||||
CrawlStack(&me, jb);
|
||||
|
||||
write(gLogFD, &me, sizeof(me) - MAX_STACK_CRAWL*sizeof(char*) +
|
||||
me.numpcs*sizeof(char*));
|
||||
}
|
||||
|
||||
static void*
|
||||
MallocHook(size_t aSize, u_long aLogType)
|
||||
{
|
||||
size_t roundedSize = aSize;
|
||||
roundedSize = ((roundedSize + 4 + gFillCount) >> 2) << 2;
|
||||
|
||||
void* ptr = REAL_MALLOC(sizeof(Header) + roundedSize + sizeof(Trailer));
|
||||
|
||||
if (NULL != ptr) {
|
||||
Header* h = (Header*) ptr;
|
||||
h->rawSize = aSize;
|
||||
h->size = roundedSize;
|
||||
h->marker0 = MARKER0;
|
||||
h->marker1 = MARKER1;
|
||||
|
||||
ptr = (void*) ((char*)(h+1));
|
||||
|
||||
// Fill new memory with a pattern to help detect overruns and
|
||||
// usage of un-written memory
|
||||
memset(ptr, PATTERN_BYTE, roundedSize);
|
||||
|
||||
Trailer* t = (Trailer*) ((char*)ptr + roundedSize);
|
||||
t->marker2[0] = MARKER2_0;
|
||||
t->marker2[1] = MARKER2_1;
|
||||
|
||||
if (LIBMALLOC_LOG & gFlags) {
|
||||
Log(aLogType, ptr, aSize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeHook(void* aAddr, u_long aLogType)
|
||||
{
|
||||
if (0 == aAddr) {
|
||||
return;
|
||||
}
|
||||
if (LIBMALLOC_LOG & gFlags) {
|
||||
Log(aLogType, aAddr, 0, 0);
|
||||
}
|
||||
Header* h = (Header*) ((char*)aAddr - sizeof(Header));
|
||||
if (Verify(h)) {
|
||||
// Munge the header so that a dup-free will fail the verify
|
||||
h->marker0 = 0xDEADBEEF;
|
||||
h->marker1 = 0xDEADBEEF;
|
||||
|
||||
// Munge the body of the allocation so that if the user
|
||||
// still has a live reference they get messed up
|
||||
void* ptr = (void*) ((char*)(h+1));
|
||||
memset(ptr, FREE_PATTERN_BYTE, h->rawSize);
|
||||
|
||||
if (0 == (LIBMALLOC_NOFREE & gFlags)) {
|
||||
REAL_FREE(h);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (0 == (LIBMALLOC_NOFREE & gFlags)) {
|
||||
REAL_FREE(aAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void*
|
||||
ReallocHook(void* aOldAddr, size_t aSize)
|
||||
{
|
||||
if (0 == aOldAddr) {
|
||||
return MallocHook(aSize, malloc_log_malloc);
|
||||
}
|
||||
Header* oldh = (Header*) ((char*)aOldAddr - sizeof(Header));
|
||||
if (!Verify(oldh)) {
|
||||
return REAL_REALLOC(aOldAddr, aSize);
|
||||
}
|
||||
size_t oldSize = oldh->rawSize;
|
||||
|
||||
size_t roundedSize = aSize;
|
||||
roundedSize = ((roundedSize + 4) >> 2) << 2;
|
||||
|
||||
void* ptr = REAL_MALLOC(sizeof(Header) + roundedSize + sizeof(Trailer));
|
||||
|
||||
if (NULL != ptr) {
|
||||
Header* h = (Header*) ptr;
|
||||
h->rawSize = aSize;
|
||||
h->size = roundedSize;
|
||||
h->marker0 = MARKER0;
|
||||
h->marker1 = MARKER1;
|
||||
|
||||
ptr = (void*) ((char*)(h+1));
|
||||
|
||||
Trailer* t = (Trailer*) ((char*)ptr + roundedSize);
|
||||
t->marker2[0] = MARKER2_0;
|
||||
t->marker2[1] = MARKER2_1;
|
||||
|
||||
// Copy old memory into new memory (don't copy too much!)
|
||||
size_t copy = oldSize;
|
||||
if (copy > aSize) copy = aSize;
|
||||
memcpy(ptr, aOldAddr, copy);
|
||||
|
||||
// Fill any uncopied memory with the overrun pattern
|
||||
size_t fill = roundedSize - copy;
|
||||
if (0 != fill) {
|
||||
memset((char*)ptr + copy, PATTERN_BYTE, fill);
|
||||
}
|
||||
|
||||
if (0 == (LIBMALLOC_NOFREE & gFlags)) {
|
||||
REAL_FREE(oldh);
|
||||
}
|
||||
else {
|
||||
// Mark the old header so that a verify will fail if the caller
|
||||
// dup free's it.
|
||||
oldh->marker0 = 0xDEADBEEF;
|
||||
oldh->marker1 = 0xDEADBEEF;
|
||||
|
||||
// Munge the body of the old allocation so that if the user
|
||||
// still has a live reference they get messed up
|
||||
void* optr = (void*) ((char*)(oldh+1));
|
||||
memset(optr, FREE_PATTERN_BYTE, oldh->rawSize);
|
||||
}
|
||||
|
||||
if (LIBMALLOC_LOG & gFlags) {
|
||||
Log(malloc_log_realloc, ptr, aSize, aOldAddr);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
u_long
|
||||
SetMallocFlags(u_long aFlags)
|
||||
{
|
||||
u_long old = gFlags;
|
||||
gFlags = aFlags;
|
||||
|
||||
if ((-1 == gLogFD) && ((LIBMALLOC_LOG|LIBMALLOC_LOG_RC) & gFlags)) {
|
||||
gLogFD = open("malloc-log", O_CREAT|O_WRONLY|O_TRUNC, 0666);
|
||||
if (gLogFD < 0) {
|
||||
gFlags &= ~LIBMALLOC_LOG;
|
||||
printf("unable to create malloc-log: %d\n", errno);
|
||||
}
|
||||
}
|
||||
if ((gLogFD >= 0) && (0 == ((LIBMALLOC_LOG|LIBMALLOC_LOG_RC) & gFlags))) {
|
||||
close(gLogFD);
|
||||
gLogFD = -1;
|
||||
}
|
||||
#ifndef NTO
|
||||
if (LIBMALLOC_CHECK & gFlags) {
|
||||
mallopt(M_CHECK_ACTION, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try to guarantee that the address map is always dumped
|
||||
atexit(DumpAddressMap);
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
static int gFirstTime = 1;
|
||||
|
||||
static void Init()
|
||||
{
|
||||
gFirstTime = 0;
|
||||
u_long flags = 0;
|
||||
char* s = getenv("LIBMALLOC_LOG");
|
||||
if (s) {
|
||||
flags = atoi(s);
|
||||
if (LIBMALLOC_LOG & flags) {
|
||||
char m1[] = "dbgmalloc: enabled memory logging\n";
|
||||
write(1, m1, sizeof(m1)-1);
|
||||
}
|
||||
if (LIBMALLOC_LOG_RC & flags) {
|
||||
char m2[] = "dbgmalloc: enabled refcnt logging\n";
|
||||
write(1, m2, sizeof(m2)-1);
|
||||
}
|
||||
if (LIBMALLOC_NOFREE & flags) {
|
||||
char m3[] = "dbgmalloc: disabled free\n";
|
||||
write(1, m3, sizeof(m3)-1);
|
||||
}
|
||||
}
|
||||
SetMallocFlags(flags);
|
||||
s = getenv("LIBMALLOC_FILL");
|
||||
if (s) {
|
||||
gFillCount = atoi(s);
|
||||
char m4[] = "dbgmalloc: adding extra memory fill ";
|
||||
write(1, m4, sizeof(m4)-1);
|
||||
write(1, s, strlen(s));
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#ifdef NEED_WRAPPERS
|
||||
void* __wrap_malloc(size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return MallocHook(aSize, malloc_log_malloc);
|
||||
}
|
||||
|
||||
void* __wrap_realloc(void* aPtr, size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return ReallocHook(aPtr, aSize);
|
||||
}
|
||||
|
||||
void __wrap_free(void* aPtr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(aPtr, malloc_log_free);
|
||||
}
|
||||
|
||||
void* __wrap___builtin_new(size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return MallocHook(aSize, malloc_log_new);
|
||||
}
|
||||
|
||||
void __wrap___builtin_delete(void* aPtr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(aPtr, malloc_log_delete);
|
||||
}
|
||||
|
||||
void* __wrap___builtin_vec_new(size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return MallocHook(aSize, malloc_log_new);
|
||||
}
|
||||
|
||||
void __wrap___builtin_vec_delete(void* aPtr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(aPtr, malloc_log_delete);
|
||||
}
|
||||
|
||||
void* __wrap_PR_Malloc(size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return MallocHook(aSize, malloc_log_malloc);
|
||||
}
|
||||
|
||||
void* __wrap_PR_Calloc(size_t aSize, size_t aBsize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
size_t size = aSize*aBsize;
|
||||
void* ptr = MallocHook(size, malloc_log_malloc);
|
||||
if (NULL != ptr) {
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* __wrap_PR_Realloc(void* aPtr, size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return ReallocHook(aPtr, aSize);
|
||||
}
|
||||
|
||||
void __wrap_PR_Free(void* aPtr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(aPtr, malloc_log_free);
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// Strong symbols so that libc references are routed to us
|
||||
|
||||
void* malloc(size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return MallocHook(aSize, malloc_log_malloc);
|
||||
}
|
||||
|
||||
void* realloc(void* aPtr, size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return ReallocHook(aPtr, aSize);
|
||||
}
|
||||
|
||||
void free(void* aPtr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(aPtr, malloc_log_free);
|
||||
}
|
||||
|
||||
void* calloc(size_t aSize, size_t aBsize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
size_t size = aSize*aBsize;
|
||||
void* ptr = MallocHook(size, malloc_log_malloc);
|
||||
if (NULL != ptr) {
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void cfree(void* ptr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(ptr, malloc_log_free);
|
||||
}
|
||||
|
||||
void* memalign(size_t alignment, size_t size)
|
||||
{
|
||||
::abort();
|
||||
}
|
||||
|
||||
void* valloc(size_t size)
|
||||
{
|
||||
::abort();
|
||||
}
|
||||
|
||||
void* pvalloc(size_t size)
|
||||
{
|
||||
::abort();
|
||||
}
|
||||
|
||||
void* __builtin_new(size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return MallocHook(aSize, malloc_log_new);
|
||||
}
|
||||
|
||||
void __builtin_delete(void* aPtr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(aPtr, malloc_log_delete);
|
||||
}
|
||||
|
||||
void* __builtin_vec_new(size_t aSize)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
return MallocHook(aSize, malloc_log_new);
|
||||
}
|
||||
|
||||
void __builtin_vec_delete(void* aPtr)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
FreeHook(aPtr, malloc_log_delete);
|
||||
}
|
||||
|
||||
void
|
||||
__log_addref(void* p, int oldrc, int newrc)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
if (LIBMALLOC_LOG_RC & gFlags) {
|
||||
Log(malloc_log_addref, p, size_t(oldrc), (void*)newrc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
__log_release(void* p, int oldrc, int newrc)
|
||||
{
|
||||
if (gFirstTime) {
|
||||
Init();
|
||||
}
|
||||
if (LIBMALLOC_LOG_RC & gFlags) {
|
||||
Log(malloc_log_release, p, size_t(oldrc), (void*)newrc);
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kipp E.B. Hickman <kipp@netscape.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef libmalloc_h___
|
||||
#define libmalloc_h___
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
typedef unsigned long u_long;
|
||||
|
||||
// Format of a malloc log entry. This is what's written out to the
|
||||
// "malloc-log" file.
|
||||
struct malloc_log_entry {
|
||||
u_long type;
|
||||
u_long address;
|
||||
u_long size;
|
||||
u_long oldaddress;
|
||||
u_long numpcs;
|
||||
char* pcs[MAX_STACK_CRAWL];
|
||||
};
|
||||
|
||||
// type's
|
||||
#define malloc_log_malloc 0
|
||||
#define malloc_log_realloc 1
|
||||
#define malloc_log_free 2
|
||||
#define malloc_log_new 3
|
||||
#define malloc_log_delete 4
|
||||
#define malloc_log_addref 5
|
||||
#define malloc_log_release 6
|
||||
|
||||
// Format of a malloc map entry; after this struct is nameLen+1 bytes of
|
||||
// name data.
|
||||
struct malloc_map_entry {
|
||||
u_long nameLen;
|
||||
u_long address; // base address
|
||||
};
|
||||
|
||||
// A method that can be called if you want to programmatically control
|
||||
// the malloc logging. Note that you must link with the library to do
|
||||
// this (or use dlsym after dynamically loading the library...)
|
||||
extern u_long SetMallocFlags(u_long flags);
|
||||
|
||||
// The environment variable LIBMALLOC_LOG should be set to an integer
|
||||
// value whose meaning is as follows:
|
||||
|
||||
// Enable logging
|
||||
#define LIBMALLOC_LOG 0x1
|
||||
|
||||
// Don't free memory when set
|
||||
#define LIBMALLOC_NOFREE 0x2
|
||||
|
||||
// Check heap for corruption after every malloc/free/realloc
|
||||
#define LIBMALLOC_CHECK 0x4
|
||||
|
||||
// Log reference count calls (addref/release)
|
||||
#define LIBMALLOC_LOG_RC 0x8
|
||||
|
||||
void __log_addref(void* p, int oldrc, int newrc);
|
||||
void __log_release(void* p, int oldrc, int newrc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* libmalloc_h___ */
|
Binary file not shown.
Before Width: | Height: | Size: 85 B |
Binary file not shown.
Before Width: | Height: | Size: 85 B |
@ -1,72 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Kipp E.B. Hickman.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "strset.h"
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
StrSet::StrSet()
|
||||
{
|
||||
strings = 0;
|
||||
numstrings = 0;
|
||||
}
|
||||
|
||||
void StrSet::add(const char* s)
|
||||
{
|
||||
if (strings) {
|
||||
strings = (char**) realloc(strings, (numstrings + 1) * sizeof(char*));
|
||||
} else {
|
||||
strings = (char**) malloc(sizeof(char*));
|
||||
}
|
||||
strings[numstrings] = strdup(s);
|
||||
numstrings++;
|
||||
}
|
||||
|
||||
int StrSet::contains(const char* s)
|
||||
{
|
||||
char** sp = strings;
|
||||
int i = numstrings;
|
||||
|
||||
while (--i >= 0) {
|
||||
char *ss = *sp++;
|
||||
if (ss[0] == s[0]) {
|
||||
if (strcmp(ss, s) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kipp E.B. Hickman <kipp@netscape.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __strset_h_
|
||||
#define __strset_h_
|
||||
|
||||
struct StrSet {
|
||||
StrSet();
|
||||
|
||||
void add(const char* string);
|
||||
int contains(const char* string);
|
||||
bool IsEmpty() const { return 0 == numstrings; }
|
||||
|
||||
char** strings;
|
||||
int numstrings;
|
||||
};
|
||||
|
||||
#endif /* __strset_h_ */
|
Loading…
Reference in New Issue
Block a user