From 03b8e91855e2ff22bbb333710d92f145ab6acf73 Mon Sep 17 00:00:00 2001 From: "dbaron%fas.harvard.edu" Date: Sat, 8 Sep 2001 18:29:24 +0000 Subject: [PATCH] Move trace-malloc readers from mozilla/xpcom/base/ to mozilla/tools/trace-malloc/. Add a --shutdown-leaks option to nsTraceMalloc to dump, to the file given as an argument to the option, information about allocations still live at shutdown. Add a new trace-malloc reader (leakstats.c) to print leak statistics. b=84831 r=jag sr=brendan --- Makefile.in | 4 + allmakefiles.sh | 6 + tools/trace-malloc/Makefile.in | 47 +++++ tools/trace-malloc/leakstats.c | 167 ++++++++++++++++++ tools/trace-malloc/lib/nsTraceMalloc.c | 228 +++++++++++++++---------- xpcom/base/Makefile.in | 4 - xpcom/base/bloatblame.c | 0 xpcom/base/nsTraceMalloc.c | 228 +++++++++++++++---------- xpcom/base/tmreader.c | 0 xpcom/base/tmreader.h | 0 10 files changed, 494 insertions(+), 190 deletions(-) create mode 100644 tools/trace-malloc/Makefile.in create mode 100644 tools/trace-malloc/leakstats.c delete mode 100644 xpcom/base/bloatblame.c delete mode 100644 xpcom/base/tmreader.c delete mode 100644 xpcom/base/tmreader.h diff --git a/Makefile.in b/Makefile.in index 205d45c3a3c..2933331a0aa 100644 --- a/Makefile.in +++ b/Makefile.in @@ -154,6 +154,10 @@ ifdef ENABLE_TESTS DIRS += xpcom/tests endif +ifdef NS_TRACE_MALLOC +DIRS += tools/trace-malloc +endif + DIRS += l10n ifneq (,$(MOZ_STATIC_COMPONENTS)$(MOZ_META_COMPONENTS)) diff --git a/allmakefiles.sh b/allmakefiles.sh index c777182fc0f..28a95530a5a 100755 --- a/allmakefiles.sh +++ b/allmakefiles.sh @@ -913,6 +913,11 @@ if [ "$MOZ_LEAKY" ]; then MAKEFILES_leaky="tools/leaky/Makefile" fi +# tools/trace-malloc +if [ "$NS_TRACE_MALLOC" ]; then + MAKEFILES_tracemalloc="tools/trace-malloc/Makefile" +fi + # layout/mathml if [ "$MOZ_MATHML" ]; then MAKEFILES_layout="$MAKEFILES_layout @@ -1123,6 +1128,7 @@ $MAKEFILES_rdf $MAKEFILES_static_components $MAKEFILES_sun_java $MAKEFILES_themes +$MAKEFILES_tracemalloc $MAKEFILES_uriloader $MAKEFILES_view $MAKEFILES_webshell diff --git a/tools/trace-malloc/Makefile.in b/tools/trace-malloc/Makefile.in new file mode 100644 index 00000000000..2bfe5f63fe1 --- /dev/null +++ b/tools/trace-malloc/Makefile.in @@ -0,0 +1,47 @@ +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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 Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +REQUIRES = string xpcom + +CSRCS += \ + bloatblame.c \ + leakstats.c \ + $(NULL) + +SIMPLE_PROGRAMS = $(CSRCS:.c=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS += \ + $(NSPR_LIBS) \ + tmreader.o \ + $(NULL) + +EXTRA_DEPS = tmreader.o + +include $(topsrcdir)/config/rules.mk diff --git a/tools/trace-malloc/leakstats.c b/tools/trace-malloc/leakstats.c new file mode 100644 index 00000000000..5b490b25d26 --- /dev/null +++ b/tools/trace-malloc/leakstats.c @@ -0,0 +1,167 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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 oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is nsTraceMalloc.c/bloatblame.c code, released + * April 19, 2000. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Brendan Eich, 14-April-2000 + * L. David Baron, 2001-06-07, created leakstats.c based on bloatblame.c + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + */ +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#else +extern int getopt(int argc, char *const *argv, const char *shortopts); +extern char *optarg; +extern int optind; +#endif +#include +#include "nsTraceMalloc.h" +#include "tmreader.h" + +static char *program; + +typedef struct handler_data { + uint32 current_heapsize; + uint32 max_heapsize; + uint32 bytes_allocated; + uint32 current_allocations; + uint32 total_allocations; + int finished; +} handler_data; + +static void handler_data_init(handler_data *data) +{ + data->current_heapsize = 0; + data->max_heapsize = 0; + data->bytes_allocated = 0; + data->current_allocations = 0; + data->total_allocations = 0; + data->finished = 0; +} + +static void handler_data_finish(handler_data *data) +{ +} + +static void my_tmevent_handler(tmreader *tmr, tmevent *event) +{ + handler_data *data = (handler_data*) tmr->data; + + switch (event->type) { + case TM_EVENT_REALLOC: + data->current_heapsize -= event->u.alloc.oldsize; + --data->current_allocations; + /* fall-through intentional */ + case TM_EVENT_MALLOC: + case TM_EVENT_CALLOC: + ++data->current_allocations; + ++data->total_allocations; + data->bytes_allocated += event->u.alloc.size; + data->current_heapsize += event->u.alloc.size; + if (data->current_heapsize > data->max_heapsize) + data->max_heapsize = data->current_heapsize; + break; + case TM_EVENT_FREE: + --data->current_allocations; + data->current_heapsize -= event->u.alloc.size; + break; + case TM_EVENT_STATS: + data->finished = 1; + break; + } +} + + +int main(int argc, char **argv) +{ + int c, i, j, rv; + tmreader *tmr; + FILE *fp; + time_t start; + handler_data data; + + program = *argv; + + handler_data_init(&data); + tmr = tmreader_new(program, &data); + if (!tmr) { + perror(program); + exit(1); + } + + start = time(NULL); + fprintf(stdout, "%s starting at %s", program, ctime(&start)); + fflush(stdout); + + argc -= optind; + argv += optind; + if (argc == 0) { + if (tmreader_eventloop(tmr, "-", my_tmevent_handler) <= 0) + exit(1); + } else { + for (i = j = 0; i < argc; i++) { + fp = fopen(argv[i], "r"); + if (!fp) { + fprintf(stderr, "%s: can't open %s: %s\n", + program, argv[i], strerror(errno)); + exit(1); + } + rv = tmreader_eventloop(tmr, argv[i], my_tmevent_handler); + if (rv < 0) + exit(1); + if (rv > 0) + j++; + fclose(fp); + } + if (j == 0) + exit(1); + } + + if (!data.finished) { + fprintf(stderr, "%s: log file incomplete\n", program); + exit(1); + } + + fprintf(stdout, + "Leaks: %u bytes, %u allocations\n" + "Maximum Heap Size: %u bytes\n" + "%u bytes were allocated in %u allocations.\n", + data.current_heapsize, data.current_allocations, + data.max_heapsize, + data.bytes_allocated, data.total_allocations); + + handler_data_finish(&data); + tmreader_destroy(tmr); + + exit(0); +} diff --git a/tools/trace-malloc/lib/nsTraceMalloc.c b/tools/trace-malloc/lib/nsTraceMalloc.c index cbeb2d928e5..5d33fdeb15c 100644 --- a/tools/trace-malloc/lib/nsTraceMalloc.c +++ b/tools/trace-malloc/lib/nsTraceMalloc.c @@ -56,6 +56,7 @@ #include "prlog.h" #include "prmon.h" #include "prprf.h" +#include "prenv.h" #include "nsTraceMalloc.h" #ifdef XP_WIN32 @@ -68,7 +69,7 @@ #define WRITE_FLAGS "w" -#endif //WIN32 +#endif /* WIN32 */ #ifdef XP_UNIX @@ -268,6 +269,7 @@ static logfile *logfile_list = NULL; static logfile **logfile_tail = &logfile_list; static logfile *logfp = &default_logfile; static PRMonitor *tmmon = NULL; +static char *sdlogname = NULL; /* filename for shutdown leak log */ /* We don't want more than 32 logfiles open at once, ok? */ typedef uint32 lfd_set; @@ -318,7 +320,7 @@ retry: static void flush_logfile(logfile *fp) { int len, cnt; - int fd; + int fd; char *bp; len = fp->pos; @@ -570,15 +572,17 @@ static callsite *calltree(int skip) if (! ok) return 0; - // Get the context information for this thread. That way we will - // know where our sp, fp, pc, etc. are and can fill in the - // STACKFRAME with the initial values. + /* + * Get the context information for this thread. That way we will + * know where our sp, fp, pc, etc. are and can fill in the + * STACKFRAME with the initial values. + */ context.ContextFlags = CONTEXT_FULL; ok = GetThreadContext(myThread, &context); if (! ok) return 0; - // Setup initial stack frame to walk from + /* Setup initial stack frame to walk from */ memset(&(frame[0]), 0, sizeof(frame[0])); frame[0].AddrPC.Offset = context.Eip; frame[0].AddrPC.Mode = AddrModeFlat; @@ -598,10 +602,11 @@ static callsite *calltree(int skip) myThread, &(frame[framenum]), &context, - 0, // read process memory routine - _SymFunctionTableAccess, // function table access routine - _SymGetModuleBase, // module base routine - 0); // translate address routine + 0, /* read process memory routine */ + _SymFunctionTableAccess, /* function table access + routine */ + _SymGetModuleBase, /* module base routine */ + 0); /* translate address routine */ if (!ok) { break; @@ -676,7 +681,7 @@ static callsite *calltree(int skip) { DWORD error = GetLastError(); PR_ASSERT(error); - library = "unknown";//ew + library = "unknown";/* ew */ } else { @@ -707,7 +712,7 @@ static callsite *calltree(int skip) hash = PL_HashString(library); hep = PL_HashTableRawLookup(libraries, hash, library); he = *hep; - library = strdup(library); //strdup it always? + library = strdup(library); /* strdup it always? */ if (he) { library_serial = (uint32) he->value; le = (lfdset_entry *) he; @@ -716,7 +721,7 @@ static callsite *calltree(int skip) le = NULL; } } else { -// library = strdup(library); +/* library = strdup(library); */ if (library) { library_serial = ++library_serial_generator; he = PL_HashTableRawAdd(libraries, hep, hash, library, @@ -1430,97 +1435,131 @@ PR_IMPLEMENT(void) NS_TraceMallocStartup(int logfd) } +/* + * Options for log files, with the log file name either as the next option + * or separated by '=' (e.g. "./mozilla --trace-malloc * malloc.log" or + * "./mozilla --trace-malloc=malloc.log"). + */ +static const char TMLOG_OPTION[] = "--trace-malloc"; +static const char SDLOG_OPTION[] = "--shutdown-leaks"; + +#define SHOULD_PARSE_ARG(name_, log_, arg_) \ + (0 == strncmp(arg_, name_, sizeof(name_) - 1)) + +#define PARSE_ARG(name_, log_, argv_, i_, consumed_) \ + PR_BEGIN_MACRO \ + char _nextchar = argv_[i_][sizeof(name_) - 1]; \ + if (_nextchar == '=') { \ + log_ = argv_[i_] + sizeof(name_); \ + consumed_ = 1; \ + } else if (_nextchar == '\0') { \ + log_ = argv_[i_+1]; \ + consumed_ = 2; \ + } \ + PR_END_MACRO PR_IMPLEMENT(int) NS_TraceMallocStartupArgs(int argc, char* argv[]) { - int i, logfd = -1; + int i, logfd = -1, consumed; + char *tmlogname = NULL; /* note global |sdlogname| */ /* * Look for the --trace-malloc option early, to avoid missing * early mallocs (we miss static constructors whose output overflows the * log file's static 16K output buffer). */ - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "--trace-malloc") == 0 && i < argc-1) { - char *logfilename; - int pipefds[2]; + for (i = 1; i < argc; i += consumed) { + consumed = 0; + if (SHOULD_PARSE_ARG(TMLOG_OPTION, tmlogname, argv[i])) + PARSE_ARG(TMLOG_OPTION, tmlogname, argv, i, consumed); + else if (SHOULD_PARSE_ARG(SDLOG_OPTION, sdlogname, argv[i])) + PARSE_ARG(SDLOG_OPTION, sdlogname, argv, i, consumed); - logfilename = argv[i+1]; - switch (*logfilename) { - #if XP_UNIX - case '|': - if (pipe(pipefds) == 0) { - pid_t pid = fork(); - if (pid == 0) { - /* In child: set up stdin, parse args, and exec. */ - int maxargc, nargc; - char **nargv, *token; - - if (pipefds[0] != 0) { - dup2(pipefds[0], 0); - close(pipefds[0]); - } - close(pipefds[1]); - - logfilename = strtok(logfilename + 1, " \t"); - maxargc = 3; - nargv = (char **) malloc((maxargc+1) * sizeof(char *)); - if (!nargv) exit(1); - nargc = 0; - nargv[nargc++] = logfilename; - while ((token = strtok(NULL, " \t")) != NULL) { - if (nargc == maxargc) { - maxargc *= 2; - nargv = (char**) - realloc(nargv, (maxargc+1) * sizeof(char*)); - if (!nargv) exit(1); - } - nargv[nargc++] = token; - } - nargv[nargc] = NULL; - - (void) setsid(); - execvp(logfilename, nargv); - exit(127); - } - - if (pid > 0) { - /* In parent: set logfd to the pipe's write side. */ - close(pipefds[0]); - logfd = pipefds[1]; - } - } - if (logfd < 0) { - fprintf(stderr, - "%s: can't pipe to trace-malloc child process %s: %s\n", - argv[0], logfilename, strerror(errno)); - exit(1); - } - break; - #endif /*XP_UNIX*/ - case '-': - /* Don't log from startup, but do prepare to log later. */ - /* XXX traditional meaning of '-' as option argument is "stdin" or "stdout" */ - if (logfilename[1] == '\0') - break; - /* FALL THROUGH */ - - default: - logfd = open(logfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (logfd < 0) { - fprintf(stderr, - "%s: can't create trace-malloc logfilename %s: %s\n", - argv[0], logfilename, strerror(errno)); - exit(1); - } - break; - } -#ifndef XP_WIN32 + if (consumed) { +#ifndef XP_WIN32 /* If we don't comment this out, it will crash Windows. */ + int j; /* Now remove --trace-malloc and its argument from argv. */ - for (argc -= 2; i < argc; i++) - argv[i] = argv[i+2]; + argc -= consumed; + for (j = i; j < argc; ++j) + argv[j] = argv[j+consumed]; argv[argc] = NULL; -#endif//if you dont comment this out it will crash windows + consumed = 0; /* don't advance next iteration */ +#endif + } else { + consumed = 1; + } + } + + if (tmlogname) { + int pipefds[2]; + + switch (*tmlogname) { + #if XP_UNIX + case '|': + if (pipe(pipefds) == 0) { + pid_t pid = fork(); + if (pid == 0) { + /* In child: set up stdin, parse args, and exec. */ + int maxargc, nargc; + char **nargv, *token; + + if (pipefds[0] != 0) { + dup2(pipefds[0], 0); + close(pipefds[0]); + } + close(pipefds[1]); + + tmlogname = strtok(tmlogname + 1, " \t"); + maxargc = 3; + nargv = (char **) malloc((maxargc+1) * sizeof(char *)); + if (!nargv) exit(1); + nargc = 0; + nargv[nargc++] = tmlogname; + while ((token = strtok(NULL, " \t")) != NULL) { + if (nargc == maxargc) { + maxargc *= 2; + nargv = (char**) + realloc(nargv, (maxargc+1) * sizeof(char*)); + if (!nargv) exit(1); + } + nargv[nargc++] = token; + } + nargv[nargc] = NULL; + + (void) setsid(); + execvp(tmlogname, nargv); + exit(127); + } + + if (pid > 0) { + /* In parent: set logfd to the pipe's write side. */ + close(pipefds[0]); + logfd = pipefds[1]; + } + } + if (logfd < 0) { + fprintf(stderr, + "%s: can't pipe to trace-malloc child process %s: %s\n", + argv[0], tmlogname, strerror(errno)); + exit(1); + } + break; + #endif /*XP_UNIX*/ + case '-': + /* Don't log from startup, but do prepare to log later. */ + /* XXX traditional meaning of '-' as option argument is "stdin" or "stdout" */ + if (tmlogname[1] == '\0') + break; + /* FALL THROUGH */ + + default: + logfd = open(tmlogname, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (logfd < 0) { + fprintf(stderr, + "%s: can't create trace-malloc log named %s: %s\n", + argv[0], tmlogname, strerror(errno)); + exit(1); + } break; } } @@ -1533,6 +1572,9 @@ PR_IMPLEMENT(void) NS_TraceMallocShutdown() { logfile *fp; + if (sdlogname) + NS_TraceMallocDumpAllocations(sdlogname); + if (tmstats.backtrace_failures) { fprintf(stderr, "TraceMalloc backtrace failures: %lu (malloc %lu dladdr %lu)\n", @@ -1683,7 +1725,7 @@ NS_TraceMallocLogTimestamp(const char *caption) #endif #if defined(XP_WIN32) struct _timeb tb; -#endif +#endif if (tmmon) diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in index ba87d910f29..813e3e68d16 100644 --- a/xpcom/base/Makefile.in +++ b/xpcom/base/Makefile.in @@ -81,10 +81,6 @@ CSRCS += nsTraceMalloc.c CPPSRCS += nsTypeInfo.cpp EXPORTS += nsTraceMalloc.h DEFINES += -DNS_TRACE_MALLOC -SIMPLE_PROGRAMS = bloatblame - -LIBS += tmreader.o $(NSPR_LIBS) -EXTRA_DEPS = tmreader.o endif XPIDLSRCS = \ diff --git a/xpcom/base/bloatblame.c b/xpcom/base/bloatblame.c deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/xpcom/base/nsTraceMalloc.c b/xpcom/base/nsTraceMalloc.c index cbeb2d928e5..5d33fdeb15c 100644 --- a/xpcom/base/nsTraceMalloc.c +++ b/xpcom/base/nsTraceMalloc.c @@ -56,6 +56,7 @@ #include "prlog.h" #include "prmon.h" #include "prprf.h" +#include "prenv.h" #include "nsTraceMalloc.h" #ifdef XP_WIN32 @@ -68,7 +69,7 @@ #define WRITE_FLAGS "w" -#endif //WIN32 +#endif /* WIN32 */ #ifdef XP_UNIX @@ -268,6 +269,7 @@ static logfile *logfile_list = NULL; static logfile **logfile_tail = &logfile_list; static logfile *logfp = &default_logfile; static PRMonitor *tmmon = NULL; +static char *sdlogname = NULL; /* filename for shutdown leak log */ /* We don't want more than 32 logfiles open at once, ok? */ typedef uint32 lfd_set; @@ -318,7 +320,7 @@ retry: static void flush_logfile(logfile *fp) { int len, cnt; - int fd; + int fd; char *bp; len = fp->pos; @@ -570,15 +572,17 @@ static callsite *calltree(int skip) if (! ok) return 0; - // Get the context information for this thread. That way we will - // know where our sp, fp, pc, etc. are and can fill in the - // STACKFRAME with the initial values. + /* + * Get the context information for this thread. That way we will + * know where our sp, fp, pc, etc. are and can fill in the + * STACKFRAME with the initial values. + */ context.ContextFlags = CONTEXT_FULL; ok = GetThreadContext(myThread, &context); if (! ok) return 0; - // Setup initial stack frame to walk from + /* Setup initial stack frame to walk from */ memset(&(frame[0]), 0, sizeof(frame[0])); frame[0].AddrPC.Offset = context.Eip; frame[0].AddrPC.Mode = AddrModeFlat; @@ -598,10 +602,11 @@ static callsite *calltree(int skip) myThread, &(frame[framenum]), &context, - 0, // read process memory routine - _SymFunctionTableAccess, // function table access routine - _SymGetModuleBase, // module base routine - 0); // translate address routine + 0, /* read process memory routine */ + _SymFunctionTableAccess, /* function table access + routine */ + _SymGetModuleBase, /* module base routine */ + 0); /* translate address routine */ if (!ok) { break; @@ -676,7 +681,7 @@ static callsite *calltree(int skip) { DWORD error = GetLastError(); PR_ASSERT(error); - library = "unknown";//ew + library = "unknown";/* ew */ } else { @@ -707,7 +712,7 @@ static callsite *calltree(int skip) hash = PL_HashString(library); hep = PL_HashTableRawLookup(libraries, hash, library); he = *hep; - library = strdup(library); //strdup it always? + library = strdup(library); /* strdup it always? */ if (he) { library_serial = (uint32) he->value; le = (lfdset_entry *) he; @@ -716,7 +721,7 @@ static callsite *calltree(int skip) le = NULL; } } else { -// library = strdup(library); +/* library = strdup(library); */ if (library) { library_serial = ++library_serial_generator; he = PL_HashTableRawAdd(libraries, hep, hash, library, @@ -1430,97 +1435,131 @@ PR_IMPLEMENT(void) NS_TraceMallocStartup(int logfd) } +/* + * Options for log files, with the log file name either as the next option + * or separated by '=' (e.g. "./mozilla --trace-malloc * malloc.log" or + * "./mozilla --trace-malloc=malloc.log"). + */ +static const char TMLOG_OPTION[] = "--trace-malloc"; +static const char SDLOG_OPTION[] = "--shutdown-leaks"; + +#define SHOULD_PARSE_ARG(name_, log_, arg_) \ + (0 == strncmp(arg_, name_, sizeof(name_) - 1)) + +#define PARSE_ARG(name_, log_, argv_, i_, consumed_) \ + PR_BEGIN_MACRO \ + char _nextchar = argv_[i_][sizeof(name_) - 1]; \ + if (_nextchar == '=') { \ + log_ = argv_[i_] + sizeof(name_); \ + consumed_ = 1; \ + } else if (_nextchar == '\0') { \ + log_ = argv_[i_+1]; \ + consumed_ = 2; \ + } \ + PR_END_MACRO PR_IMPLEMENT(int) NS_TraceMallocStartupArgs(int argc, char* argv[]) { - int i, logfd = -1; + int i, logfd = -1, consumed; + char *tmlogname = NULL; /* note global |sdlogname| */ /* * Look for the --trace-malloc option early, to avoid missing * early mallocs (we miss static constructors whose output overflows the * log file's static 16K output buffer). */ - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "--trace-malloc") == 0 && i < argc-1) { - char *logfilename; - int pipefds[2]; + for (i = 1; i < argc; i += consumed) { + consumed = 0; + if (SHOULD_PARSE_ARG(TMLOG_OPTION, tmlogname, argv[i])) + PARSE_ARG(TMLOG_OPTION, tmlogname, argv, i, consumed); + else if (SHOULD_PARSE_ARG(SDLOG_OPTION, sdlogname, argv[i])) + PARSE_ARG(SDLOG_OPTION, sdlogname, argv, i, consumed); - logfilename = argv[i+1]; - switch (*logfilename) { - #if XP_UNIX - case '|': - if (pipe(pipefds) == 0) { - pid_t pid = fork(); - if (pid == 0) { - /* In child: set up stdin, parse args, and exec. */ - int maxargc, nargc; - char **nargv, *token; - - if (pipefds[0] != 0) { - dup2(pipefds[0], 0); - close(pipefds[0]); - } - close(pipefds[1]); - - logfilename = strtok(logfilename + 1, " \t"); - maxargc = 3; - nargv = (char **) malloc((maxargc+1) * sizeof(char *)); - if (!nargv) exit(1); - nargc = 0; - nargv[nargc++] = logfilename; - while ((token = strtok(NULL, " \t")) != NULL) { - if (nargc == maxargc) { - maxargc *= 2; - nargv = (char**) - realloc(nargv, (maxargc+1) * sizeof(char*)); - if (!nargv) exit(1); - } - nargv[nargc++] = token; - } - nargv[nargc] = NULL; - - (void) setsid(); - execvp(logfilename, nargv); - exit(127); - } - - if (pid > 0) { - /* In parent: set logfd to the pipe's write side. */ - close(pipefds[0]); - logfd = pipefds[1]; - } - } - if (logfd < 0) { - fprintf(stderr, - "%s: can't pipe to trace-malloc child process %s: %s\n", - argv[0], logfilename, strerror(errno)); - exit(1); - } - break; - #endif /*XP_UNIX*/ - case '-': - /* Don't log from startup, but do prepare to log later. */ - /* XXX traditional meaning of '-' as option argument is "stdin" or "stdout" */ - if (logfilename[1] == '\0') - break; - /* FALL THROUGH */ - - default: - logfd = open(logfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (logfd < 0) { - fprintf(stderr, - "%s: can't create trace-malloc logfilename %s: %s\n", - argv[0], logfilename, strerror(errno)); - exit(1); - } - break; - } -#ifndef XP_WIN32 + if (consumed) { +#ifndef XP_WIN32 /* If we don't comment this out, it will crash Windows. */ + int j; /* Now remove --trace-malloc and its argument from argv. */ - for (argc -= 2; i < argc; i++) - argv[i] = argv[i+2]; + argc -= consumed; + for (j = i; j < argc; ++j) + argv[j] = argv[j+consumed]; argv[argc] = NULL; -#endif//if you dont comment this out it will crash windows + consumed = 0; /* don't advance next iteration */ +#endif + } else { + consumed = 1; + } + } + + if (tmlogname) { + int pipefds[2]; + + switch (*tmlogname) { + #if XP_UNIX + case '|': + if (pipe(pipefds) == 0) { + pid_t pid = fork(); + if (pid == 0) { + /* In child: set up stdin, parse args, and exec. */ + int maxargc, nargc; + char **nargv, *token; + + if (pipefds[0] != 0) { + dup2(pipefds[0], 0); + close(pipefds[0]); + } + close(pipefds[1]); + + tmlogname = strtok(tmlogname + 1, " \t"); + maxargc = 3; + nargv = (char **) malloc((maxargc+1) * sizeof(char *)); + if (!nargv) exit(1); + nargc = 0; + nargv[nargc++] = tmlogname; + while ((token = strtok(NULL, " \t")) != NULL) { + if (nargc == maxargc) { + maxargc *= 2; + nargv = (char**) + realloc(nargv, (maxargc+1) * sizeof(char*)); + if (!nargv) exit(1); + } + nargv[nargc++] = token; + } + nargv[nargc] = NULL; + + (void) setsid(); + execvp(tmlogname, nargv); + exit(127); + } + + if (pid > 0) { + /* In parent: set logfd to the pipe's write side. */ + close(pipefds[0]); + logfd = pipefds[1]; + } + } + if (logfd < 0) { + fprintf(stderr, + "%s: can't pipe to trace-malloc child process %s: %s\n", + argv[0], tmlogname, strerror(errno)); + exit(1); + } + break; + #endif /*XP_UNIX*/ + case '-': + /* Don't log from startup, but do prepare to log later. */ + /* XXX traditional meaning of '-' as option argument is "stdin" or "stdout" */ + if (tmlogname[1] == '\0') + break; + /* FALL THROUGH */ + + default: + logfd = open(tmlogname, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (logfd < 0) { + fprintf(stderr, + "%s: can't create trace-malloc log named %s: %s\n", + argv[0], tmlogname, strerror(errno)); + exit(1); + } break; } } @@ -1533,6 +1572,9 @@ PR_IMPLEMENT(void) NS_TraceMallocShutdown() { logfile *fp; + if (sdlogname) + NS_TraceMallocDumpAllocations(sdlogname); + if (tmstats.backtrace_failures) { fprintf(stderr, "TraceMalloc backtrace failures: %lu (malloc %lu dladdr %lu)\n", @@ -1683,7 +1725,7 @@ NS_TraceMallocLogTimestamp(const char *caption) #endif #if defined(XP_WIN32) struct _timeb tb; -#endif +#endif if (tmmon) diff --git a/xpcom/base/tmreader.c b/xpcom/base/tmreader.c deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/xpcom/base/tmreader.h b/xpcom/base/tmreader.h deleted file mode 100644 index e69de29bb2d..00000000000