Bug 750290 - Remove tools/leaky. r=dbaron

This commit is contained in:
Mike Hommey 2012-04-30 18:17:46 +02:00
parent 28ffb279a2
commit e551920d94
32 changed files with 0 additions and 3393 deletions

View File

@ -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@

View File

@ -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)

View File

@ -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@

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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-*

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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___ */

View File

@ -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;
}
}

View File

@ -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_ */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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>&nbsp;
<pre>&nbsp; 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>&nbsp;
<pre>&nbsp; ./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 &lt;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 &lt;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>&nbsp;
<br><tt>(gdb) p DumpAddressMap()</tt></ol>
<li>
Then use leaky to capture the addref and release calls to a log file:</li>
<ol>&nbsp;
<br><tt>leaky -d -a &lt;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>&nbsp; leaky -gqx &lt;program-name-goes-here>&nbsp; malloc-log | sed -e 's/&amp;/&amp;/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>&nbsp;
<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>&nbsp;</td>
<td>&nbsp;</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>&nbsp;</td>
<td>&nbsp;</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>&nbsp;</td>
<td>&nbsp;</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 &lt;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>&nbsp;
<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>&nbsp;
</body>
</html>

View File

@ -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");
}
}
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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_ */