diff --git a/toolkit/xre/Makefile.in b/toolkit/xre/Makefile.in
index db8be9e2c1ec6305d9a871808c41e8d75ccd689f..39fd8ac310d1eca8486496e3eed213713a3a6387 100644
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -164,15 +164,6 @@ CMMSRCS = MacApplicationDelegate.mm
 endif
 
 ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH)))
-STACKWALK_SRC_LCSRCS =               \
-		nsStackFrameUnix.cpp \
-		nsStackFrameUnix.h   \
-		$(NULL)
-
-STACKWALK_CPPSRCS := $(addprefix $(topsrcdir)/xpcom/base/, $(STACKWALK_SRC_LCSRCS))
-ifndef MOZ_ENABLE_LIBXUL
-CPPSRCS           += nsStackFrameUnix.cpp
-endif
 SHAREDCPPSRCS	  += nsSigHandlers.cpp
 endif
 
@@ -181,10 +172,6 @@ ifeq ($(OS_ARCH),WINNT)
 GARBAGE	+= $(addprefix $(srcdir)/,$(SHAREDCPPSRCS))
 endif
 
-ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH)))
-GARBAGE += $(STACKWALK_SRC_LCSRCS)
-endif
-
 SHARED_LIBRARY_LIBS += ../profile/src/$(LIB_PREFIX)profile_s.$(LIB_SUFFIX)
 
 ifdef MOZ_ENABLE_XREMOTE
@@ -254,7 +241,7 @@ ifdef WRAP_SYSTEM_INCLUDES
 DEFINES		+= -DWRAP_SYSTEM_INCLUDES
 endif
 
-export:: $(addprefix $(topsrcdir)/xpfe/bootstrap/, $(SHAREDCPPSRCS)) $(STACKWALK_CPPSRCS)
+export:: $(addprefix $(topsrcdir)/xpfe/bootstrap/, $(SHAREDCPPSRCS))
 	$(INSTALL) $^ .
 
 platform.ini: FORCE
diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in
index 69e23cc7b4a312d155a938560fbdcea784db6ca0..78ffbd010530559895e80ec6364619b80e1a44ce 100644
--- a/xpcom/base/Makefile.in
+++ b/xpcom/base/Makefile.in
@@ -65,6 +65,7 @@ CPPSRCS		= \
 		nsUUIDGenerator.cpp \
 		nsSystemInfo.cpp \
 		nsCycleCollector.cpp \
+		nsStackWalk.cpp \
 		$(NULL)
 
 ifdef GC_LEAK_DETECTOR
@@ -85,6 +86,7 @@ EXPORTS		= \
 		nsIAllocator.h \
 		nsIID.h \
 		nsISupportsObsolete.h \
+		nsStackWalk.h \
 		nsTraceRefcntImpl.h \
 		nsWeakPtr.h \
 		nsInterfaceRequestorAgg.h \
@@ -95,11 +97,6 @@ ifdef MOZ_DEBUG
 CSRCS		+= pure_api.c
 EXPORTS		+= pure.h
 endif
-CPPSRCS		+= nsStackFrameWin.cpp
-endif
-
-ifneq ($(OS_ARCH),WINNT)
-CPPSRCS		+= nsStackFrameUnix.cpp
 endif
 
 SDK_XPIDLSRCS   = \
diff --git a/xpcom/base/nsStackFrameUnix.cpp b/xpcom/base/nsStackFrameUnix.cpp
index c896302cf92edaaefb55f83c8bf804ce9eee074b..6040e4942e745ff58766e9356452e379a099c654 100644
--- a/xpcom/base/nsStackFrameUnix.cpp
+++ b/xpcom/base/nsStackFrameUnix.cpp
@@ -37,11 +37,11 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsStackFrameUnix.h"
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
 #include "nscore.h"
+#include <stdio.h>
 
 // On glibc 2.1, the Dl_info api defined in <dlfcn.h> is only exposed
 // if __USE_GNU is defined.  I suppose its some kind of standards
@@ -86,9 +86,12 @@ void DemangleSymbol(const char * aSymbol,
 #if defined(linux) && defined(__GNUC__) && (defined(__i386) || defined(PPC) || defined(__x86_64__)) // i386 or PPC Linux stackwalking code
 
 
-void DumpStackToFile(FILE* aStream)
+EXPORT_XPCOM_API(nsresult)
+NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
+             void *aClosure)
 {
   // Stack walking code courtesy Kipp's "leaky".
+  char buf[512];
 
   // Get the frame pointer
   void **bp;
@@ -103,14 +106,15 @@ void DumpStackToFile(FILE* aStream)
   bp = (void**) __builtin_frame_address(0);
 #endif
 
-  int skip = 2;
+  int skip = aSkipFrames;
   for ( ; (void**)*bp > bp; bp = (void**)*bp) {
     void *pc = *(bp+1);
-    if (--skip <= 0) {
+    if (--skip < 0) {
       Dl_info info;
       int ok = dladdr(pc, &info);
       if (!ok) {
-        fprintf(aStream, "UNKNOWN %p\n", pc);
+        snprintf(buf, sizeof(buf), "UNKNOWN %p\n", pc);
+        (*aCallback)(buf, aClosure);
         continue;
       }
 
@@ -119,8 +123,9 @@ void DumpStackToFile(FILE* aStream)
       const char * symbol = info.dli_sname;
       int len;
       if (!symbol || !(len = strlen(symbol))) {
-        fprintf(aStream, "UNKNOWN [%s +0x%08X]\n",
-                info.dli_fname, foff);
+        snprintf(buf, sizeof(buf), "UNKNOWN [%s +0x%08X]\n",
+                                   info.dli_fname, foff);
+        (*aCallback)(buf, aClosure);
         continue;
       }
 
@@ -134,10 +139,12 @@ void DumpStackToFile(FILE* aStream)
       }
 
       PRUint32 off = (char*)pc - (char*)info.dli_saddr;
-      fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n",
-              symbol, off, info.dli_fname, foff);
+      snprintf(buf, sizeof(buf), "%s+0x%08X [%s +0x%08X]\n",
+                                 symbol, off, info.dli_fname, foff);
+      (*aCallback)(buf, aClosure);
     }
   }
+  return NS_OK;
 }
 
 #elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))
@@ -152,16 +159,15 @@ void DumpStackToFile(FILE* aStream)
 #include <sys/regset.h>
 #include <sys/stack.h>
 
-static int    load_address ( void * pc, void * arg, FILE * aStream );
-static int    write_address_file ( void * pc );
+static int    load_address ( void * pc, void * arg );
 static struct bucket * newbucket ( void * pc );
 static struct frame * cs_getmyframeptr ( void );
 static void   cs_walk_stack ( void * (*read_func)(char * address),
                               struct frame * fp,
                               int (*operate_func)(void *, void *),
-                              void * usrarg, FILE * aStream );
+                              void * usrarg );
 static void   cs_operate ( void (*operate_func)(void *, void *),
-                           void * usrarg, FILE * aStream );
+                           void * usrarg );
 
 #ifndef STACK_BIAS
 #define STACK_BIAS 0
@@ -190,9 +196,10 @@ struct bucket {
     struct bucket * next;
 };
 
-struct mybuf {
-    char * buffer;
-    int chars_left;
+struct my_user_args {
+    NS_WalkStackCallback callback;
+    PRUint32 skipFrames;
+    void *closure;
 };
 
 
@@ -225,11 +232,12 @@ myinit()
 
 
 static int
-write_address_file(void * pc, FILE* aStream)
+load_address(void * pc, void * arg )
 {
     static struct bucket table[2048];
     static mutex_t lock;
     struct bucket * ptr;
+    struct my_user_args * args = (struct my_user_args *) arg;
 
     unsigned int val = NS_PTR_TO_INT32(pc);
 
@@ -244,7 +252,6 @@ write_address_file(void * pc, FILE* aStream)
 
     if (ptr->next) {
         mutex_unlock(&lock);
-        return (ptr->next->index);
     } else {
         char buffer[4096], dembuff[4096];
         Dl_info info;
@@ -269,37 +276,12 @@ write_address_file(void * pc, FILE* aStream)
         if (strlen(dembuff)) {
             func = dembuff;
         }
-        fprintf(aStream, "%u %s:%s+0x%x\n",
-                ptr->next->index,
-                lib,
-                func,
-                (char *)pc - (char*)info.dli_saddr);
- 
-        return (ptr->next->index);
+        snprintf(buffer, sizeof(buffer), "%u %s:%s+0x%x\n",
+                 ptr->next->index, lib, func,
+                 (char *)pc - (char*)info.dli_saddr);
+        (*args.callback)(buffer, args.closure);
     }
-}
-
-
-static int
-load_address(void * pc, void * arg, FILE * aStream)
-{
-    struct mybuf * buf = (struct mybuf *) arg;
-
-    char name[80];
-    int len;
-
-    sprintf(name, " %u", write_address_file(pc, aStream));
-
-    len = strlen(name);
-
-    if (len >= buf->chars_left)
-        return (1);
-
-    strcat(buf->buffer, name);
-
-    buf->chars_left -= len;
-
-    return (0);
+    return 0;
 }
 
 
@@ -336,12 +318,12 @@ csgetframeptr()
 
 static void
 cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *),
-    void *usrarg, FILE * aStream)
+    void *usrarg)
 {
 
     while (fp != 0 && fp->fr_savpc != 0) {
 
-        if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0)
+        if (operate_func((void *)fp->fr_savpc, usrarg) != 0)
             break;
         /*
          * watch out - libthread stacks look funny at the top
@@ -355,21 +337,24 @@ cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *),
 
 
 static void
-cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream)
+cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg)
 {
-    cswalkstack(csgetframeptr(), operate_func, usrarg, aStream);
+    cswalkstack(csgetframeptr(), operate_func, usrarg);
 }
 
-void DumpStackToFile(FILE* aStream)
+EXPORT_XPCOM_API(nsresult)
+NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
+             void *aClosure)
 {
-    char buffer[LOGSIZE];
-    struct mybuf mybuf;
+    struct my_user_args args;
 
     if (!initialized)
         myinit();
 
-    mybuf.chars_left = LOGSIZE - strlen(buffer)-1;
-    mybuf.buffer = buffer;
-    cs_operate(load_address, &mybuf, aStream);
+    args.callback = aCallback;
+    args.skipFrames = aSkipFrames; /* XXX Not handled! */
+    args.closure = aClosure;
+    cs_operate(load_address, &args);
+    return NS_OK;
 }
 #endif
diff --git a/xpcom/base/nsStackFrameWin.cpp b/xpcom/base/nsStackFrameWin.cpp
index 4bfacb6fc32f50a2810f283d8c2ff27274b7a846..989faee3fe3df2fd5265270bb1ba46f42046649b 100644
--- a/xpcom/base/nsStackFrameWin.cpp
+++ b/xpcom/base/nsStackFrameWin.cpp
@@ -39,8 +39,8 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nscore.h"
-#include "windows.h"
-#include "stdio.h"
+#include <windows.h>
+#include <stdio.h>
 #include "nsStackFrameWin.h"
 
 // Define these as static pointers so that we can load the DLL on the
@@ -122,8 +122,8 @@ HANDLE hStackWalkMutex;
 PR_END_EXTERN_C
 
 // Routine to print an error message to standard error.
-// Will also print to an additional stream if one is supplied.
-void PrintError(char *prefix, FILE *out)
+// Will also call callback with error, if data supplied.
+void PrintError(char *prefix, WalkStackData *data)
 {
     LPVOID lpMsgBuf;
     DWORD lastErr = GetLastError();
@@ -136,9 +136,11 @@ void PrintError(char *prefix, FILE *out)
       0,
       NULL
     );
-    fprintf(stderr, "### ERROR: %s: %s", prefix, lpMsgBuf);
-    if (out)
-        fprintf(out, "### ERROR: %s: %s\n", prefix, lpMsgBuf);
+    char buf[512];
+    _snprintf(buf, sizeof(buf), "### ERROR: %s: %s", prefix, lpMsgBuf);
+    fputs(buf, stderr);
+    if (data)
+        (*data->callback)(buf, data->closure);
     LocalFree( lpMsgBuf );
 }
 
@@ -443,16 +445,17 @@ EnsureSymInitialized()
  * whose in memory address doesn't match its in-file address.
  */
 
-void
-DumpStackToFile(FILE* aStream)
+EXPORT_XPCOM_API(nsresult)
+NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
+             void *aClosure)
 {
     HANDLE myProcess = ::GetCurrentProcess();
     HANDLE myThread, walkerThread;
     DWORD walkerReturn;
-    struct DumpStackToFileData data;
+    struct WalkStackData data;
 
     if (!EnsureSymInitialized())
-        return;
+        return NS_ERROR_FAILURE;
 
     // Have to duplicate handle to get a real handle.
     ::DuplicateHandle(
@@ -463,43 +466,45 @@ DumpStackToFile(FILE* aStream)
       THREAD_ALL_ACCESS, FALSE, 0
     );
 
-    data.stream = aStream;
+    data.callback = aCallback;
+    data.skipFrames = aSkipFrames;
+    data.closure = aClosure;
     data.thread = myThread;
     data.process = myProcess;
-    walkerThread = ::CreateThread( NULL, 0, DumpStackToFileThread, (LPVOID) &data, 0, NULL ) ;
+    walkerThread = ::CreateThread( NULL, 0, WalkStackThread, (LPVOID) &data, 0, NULL ) ;
     if (walkerThread) {
         walkerReturn = ::WaitForSingleObject(walkerThread, 2000); // no timeout is never a good idea
         if (walkerReturn != WAIT_OBJECT_0) {
-            PrintError("ThreadWait", aStream);
+            PrintError("ThreadWait", &data);
         }
         CloseHandle(myThread);
     }
     else {
-        PrintError("ThreadCreate", aStream);
+        PrintError("ThreadCreate", &data);
     }
-    return;
+    return NS_OK;
 }
 
 DWORD WINAPI
-DumpStackToFileThread(LPVOID lpdata)
+WalkStackThread(LPVOID lpdata)
 {
-    struct DumpStackToFileData *data = (DumpStackToFileData *)lpdata;
+    struct WalkStackData *data = (WalkStackData *)lpdata;
     DWORD ret ;
 
     // Suspend the calling thread, dump his stack, and then resume him.
     // He's currently waiting for us to finish so now should be a good time.
     ret = ::SuspendThread( data->thread );
     if (ret == -1) {
-        PrintError("ThreadSuspend", data->stream);
+        PrintError("ThreadSuspend", data);
     }
     else {
         if (_StackWalk64)
-            DumpStackToFileMain64(data);
+            WalkStackMain64(data);
         else
-            DumpStackToFileMain(data);
+            WalkStackMain(data);
         ret = ::ResumeThread(data->thread);
         if (ret == -1) {
-            PrintError("ThreadResume", data->stream);
+            PrintError("ThreadResume", data);
         }
     }
 
@@ -507,7 +512,7 @@ DumpStackToFileThread(LPVOID lpdata)
 }
 
 void
-DumpStackToFileMain64(struct DumpStackToFileData* data)
+WalkStackMain64(struct WalkStackData* data)
 {
 #ifdef USING_WXP_VERSION
     // Get the context information for the thread. That way we will
@@ -516,17 +521,17 @@ DumpStackToFileMain64(struct DumpStackToFileData* data)
     CONTEXT context;
     HANDLE myProcess = data->process;
     HANDLE myThread = data->thread;
-    FILE* aStream = data->stream;
+    char buf[512];
     DWORD64 addr;
     STACKFRAME64 frame64;
-    int skip = 6; // skip our own stack walking frames
+    int skip = 3 + data->skipFrames; // skip our own stack walking frames
     BOOL ok;
 
     // Get a context for the specified thread.
     memset(&context, 0, sizeof(CONTEXT));
     context.ContextFlags = CONTEXT_FULL;
     if (!GetThreadContext(myThread, &context)) {
-        PrintError("GetThreadContext", aStream);
+        PrintError("GetThreadContext", data);
         return;
     }
 
@@ -545,7 +550,7 @@ DumpStackToFileMain64(struct DumpStackToFileData* data)
     frame64.AddrStack.Offset = context.SP;
     frame64.AddrFrame.Offset = context.RsBSP;
 #else
-    fprintf(aStream, "Unknown platform. No stack walking.");
+    PrintError("Unknown platform. No stack walking.", data);
     return;
 #endif
     frame64.AddrPC.Mode      = AddrModeFlat;
@@ -586,7 +591,7 @@ DumpStackToFileMain64(struct DumpStackToFileData* data)
             if (ok)
                 addr = frame64.AddrPC.Offset;
             else
-                PrintError("WalkStack64", aStream);
+                PrintError("WalkStack64", data);
 
             if (!ok || (addr == 0)) {
                 ReleaseMutex(hStackWalkMutex);  // release our lock
@@ -621,16 +626,17 @@ DumpStackToFileMain64(struct DumpStackToFileData* data)
             ReleaseMutex(hStackWalkMutex);
 
             if (ok)
-                fprintf(aStream, "%s!%s+0x%016X\n", modInfo.ModuleName, pSymbol->Name, displacement);
+                _snprintf(buf, sizeof(buf), "%s!%s+0x%016X\n", modInfo.ModuleName, pSymbol->Name, displacement);
             else
-                fprintf(aStream, "0x%016X\n", addr);
+                _snprintf(buf, sizeof(buf), "0x%016X\n", addr);
+            (*data->callback)(buf, data->closure);
 
             // Stop walking when we get to kernel32.
             if (strcmp(modInfo.ModuleName, "kernel32") == 0)
                 break;
         }
         else {
-            PrintError("LockError64", aStream);
+            PrintError("LockError64", data);
         } 
     }
     return;
@@ -639,7 +645,7 @@ DumpStackToFileMain64(struct DumpStackToFileData* data)
 
 
 void
-DumpStackToFileMain(struct DumpStackToFileData* data)
+WalkStackMain(struct WalkStackData* data)
 {
     // Get the context information for the thread. That way we will
     // know where our sp, fp, pc, etc. are and can fill in the
@@ -647,17 +653,17 @@ DumpStackToFileMain(struct DumpStackToFileData* data)
     CONTEXT context;
     HANDLE myProcess = data->process;
     HANDLE myThread = data->thread;
-    FILE* aStream = data->stream;
+    char buf[512];
     DWORD addr;
     STACKFRAME frame;
-    int skip = 2;  // skip our own stack walking frames
+    int skip = data->skipFrames; // skip our own stack walking frames
     BOOL ok;
 
     // Get a context for the specified thread.
     memset(&context, 0, sizeof(CONTEXT));
     context.ContextFlags = CONTEXT_FULL;
     if (!GetThreadContext(myThread, &context)) {
-        PrintError("GetThreadContext", aStream);
+        PrintError("GetThreadContext", data);
         return;
     }
 
@@ -671,7 +677,7 @@ DumpStackToFileMain(struct DumpStackToFileData* data)
     frame.AddrFrame.Offset = context.Ebp;
     frame.AddrFrame.Mode   = AddrModeFlat;
 #else
-    fprintf(aStream, "Unknown platform. No stack walking.");
+    PrintError("Unknown platform. No stack walking.", data);
     return;
 #endif
 
@@ -700,7 +706,7 @@ DumpStackToFileMain(struct DumpStackToFileData* data)
             if (ok)
                 addr = frame.AddrPC.Offset;
             else
-                PrintError("WalkStack", aStream);
+                PrintError("WalkStack", data);
 
             if (!ok || (addr == 0)) {
                 ReleaseMutex(hStackWalkMutex);  // release our lock
@@ -750,9 +756,10 @@ DumpStackToFileMain(struct DumpStackToFileData* data)
             ReleaseMutex(hStackWalkMutex);
 
             if (ok)
-                fprintf(aStream, "%s!%s+0x%08X\n", modInfo.ImageName, pSymbol->Name, displacement);
+                _snprintf(buf, sizeof(buf), "%s!%s+0x%08X\n", modInfo.ImageName, pSymbol->Name, displacement);
             else
-                fprintf(aStream, "0x%08X\n", (DWORD) addr);
+                _snprintf(buf, sizeof(buf), "0x%08X\n", (DWORD) addr);
+            (*data->callback)(buf, data->closure);
 
             // Stop walking when we get to kernel32.dll.
             if (strcmp(modInfo.ImageName, "kernel32.dll") == 0)
@@ -760,7 +767,7 @@ DumpStackToFileMain(struct DumpStackToFileData* data)
 
         }
         else {
-            PrintError("LockError", aStream);
+            PrintError("LockError", data);
         }
         
     }
diff --git a/xpcom/base/nsStackFrameWin.h b/xpcom/base/nsStackFrameWin.h
index b755b8151d2b21b554c9664c63dd54a0081ad51e..9867db22fc2247f3d84777387a4a81e6d11167ec 100644
--- a/xpcom/base/nsStackFrameWin.h
+++ b/xpcom/base/nsStackFrameWin.h
@@ -175,17 +175,18 @@ PRBool EnsureImageHlpInitialized();
  */
 BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo);
 
-struct DumpStackToFileData {
-  FILE *stream;
+struct WalkStackData {
+  NS_WalkStackCallback callback;
+  PRUint32 skipFrames;
+  void *closure;
   HANDLE thread;
   HANDLE process;
 };
 
-void PrintError(char *prefix, FILE* out);
-void DumpStackToFile(FILE* out);
-DWORD WINAPI  DumpStackToFileThread(LPVOID data);
-void DumpStackToFileMain64(struct DumpStackToFileData* data);
-void DumpStackToFileMain(struct DumpStackToFileData* data);
+void PrintError(char *prefix, WalkStackData* data);
+DWORD WINAPI  WalkStackThread(LPVOID data);
+void WalkStackMain64(struct WalkStackData* data);
+void WalkStackMain(struct WalkStackData* data);
 
 
 PR_END_EXTERN_C
diff --git a/xpcom/base/nsStackWalk.cpp b/xpcom/base/nsStackWalk.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..42a1a4e63d9a2458ad33f567b38e020f93037271
--- /dev/null
+++ b/xpcom/base/nsStackWalk.cpp
@@ -0,0 +1,59 @@
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+/* ***** 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 NS_WalkTheStack.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (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 ***** */
+
+/* API for getting a stack trace of the C/C++ stack on the current thread */
+
+#include "nsStackWalk.h"
+
+#if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code
+#include "nsStackFrameWin.cpp"
+
+// WIN32 x86 stack walking code
+// i386 or PPC Linux stackwalking code or Solaris
+#elif (defined(linux) && defined(__GNUC__) && (defined(__i386) || defined(PPC) || defined(__x86_64__))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)))
+#include "nsStackFrameUnix.cpp"
+
+#else // unsupported platform.
+
+EXPORT_XPCOM_API(nsresult)
+NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
+             void *aClosure)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#endif
diff --git a/xpcom/base/nsStackWalk.h b/xpcom/base/nsStackWalk.h
new file mode 100644
index 0000000000000000000000000000000000000000..83e075f0b9fd561ade7bdf2949a5db75a01784a7
--- /dev/null
+++ b/xpcom/base/nsStackWalk.h
@@ -0,0 +1,74 @@
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+/* ***** 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 NS_WalkTheStack.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (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 ***** */
+
+/* API for getting a stack trace of the C/C++ stack on the current thread */
+
+#ifndef nsStackWalk_h_
+#define nsStackWalk_h_
+
+/* WARNING: This file is intended to be included from C or C++ files. */
+
+#include "nscore.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef void
+(* PR_CALLBACK NS_WalkStackCallback)(char *aFrame, void *aClosure);
+
+/**
+ * Call aCallback for the C/C++ stack frames on the current thread, from
+ * the caller of NS_StackWalk to main (or above).
+ *
+ * @param aCallback    Callback function, called once per frame.
+ * @param aSkipFrames  Number of initial frames to skip.  0 means that
+ *                     the first callback will be for the caller of
+ *                     NS_StackWalk.
+ * @param aClosure     Caller-supplied data passed through to aCallback.
+ *
+ * Returns NS_ERROR_NOT_IMPLEMENTED on platforms where it is
+ * unimplemented.
+ *
+ * May skip some stack frames due to compiler optimizations or code
+ * generation.
+ */
+XPCOM_API(nsresult)
+NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
+             void *aClosure);
+
+PR_END_EXTERN_C
+
+#endif /* !defined(nsStackWalk_h_) */
diff --git a/xpcom/base/nsTraceRefcntImpl.cpp b/xpcom/base/nsTraceRefcntImpl.cpp
index a666c4755d870528e5bedcf3fc28d836a06e13d5..5241ced52f68291d925679bd86df4cff5688412d 100644
--- a/xpcom/base/nsTraceRefcntImpl.cpp
+++ b/xpcom/base/nsTraceRefcntImpl.cpp
@@ -48,9 +48,11 @@
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include <math.h>
+#include "nsStackWalk.h"
 
 #if defined(_WIN32)
 #include <windows.h>
+#include "nsStackFrameWin.h" // XXX LoadLibrarySymbols no longer belongs here
 #endif
 
 #ifdef HAVE_LIBDL
@@ -825,34 +827,22 @@ static void InitTraceLog(void)
 
 #endif
 
-#if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code
-#include "nsStackFrameWin.h"
-NS_COM void
-nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
-{
-  DumpStackToFile(aStream);
-}
+extern "C" {
 
-// WIN32 x86 stack walking code
-// i386 or PPC Linux stackwalking code or Solaris
-#elif (defined(linux) && defined(__GNUC__) && (defined(__i386) || defined(PPC) || defined(__x86_64__))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)))
-#include "nsStackFrameUnix.h"
-NS_COM void
-nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
+PR_STATIC_CALLBACK(void) PrintStackFrame(char *aFrame, void *aClosure)
 {
-  DumpStackToFile(aStream);
+  FILE *stream = (FILE*)aClosure;
+  fprintf(stream, aFrame);
 }
 
-#else // unsupported platform.
+}
 
 NS_COM void
 nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
 {
-	fprintf(aStream, "write me, dammit!\n");
+  NS_StackWalk(PrintStackFrame, 2, aStream);
 }
 
-#endif
-
 //----------------------------------------------------------------------
 
 // This thing is exported by libstdc++
diff --git a/xpfe/bootstrap/nsSigHandlers.cpp b/xpfe/bootstrap/nsSigHandlers.cpp
index acf387979f21fea8bde218e49261bf54d2ceb1b8..7b75dbb3a45f42a902ac8a94a3d5a3e106855c62 100644
--- a/xpfe/bootstrap/nsSigHandlers.cpp
+++ b/xpfe/bootstrap/nsSigHandlers.cpp
@@ -114,7 +114,16 @@ void abnormal_exit_handler(int signum)
 
 #include <unistd.h>
 #include "nsISupportsUtils.h"
-#include "nsStackFrameUnix.h"
+#include "nsStackWalk.h"
+
+extern "C" {
+
+PR_STATIC_CALLBACK(void) PrintStackFrame(char *aFrame, void *aClosure)
+{
+  fprintf(stdout, aFrame);
+}
+
+}
 
 void
 ah_crap_handler(int signum)
@@ -125,7 +134,7 @@ ah_crap_handler(int signum)
          signum);
 
   printf("Stack:\n");
-  DumpStackToFile(stdout);
+  NS_StackWalk(PrintStackFrame, 2, nsnull);
 
   printf("Sleeping for %d seconds.\n",_gdb_sleep_duration);
   printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",