summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp
new file mode 100644
index 00000000..11fe0fca
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp
@@ -0,0 +1,375 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** 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 nsStackFrameWin.h code, released
+ * December 20, 2000.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * 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 ***** */
+
+#include "nsStackFrameUnix.h"
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "nscore.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
+// adherence thing.
+//
+#if (__GLIBC_MINOR__ >= 1) && !defined(__USE_GNU)
+#define __USE_GNU
+#endif
+
+#ifdef HAVE_LIBDL
+#include <dlfcn.h>
+#endif
+
+
+
+// This thing is exported by libstdc++
+// Yes, this is a gcc only hack
+#if defined(MOZ_DEMANGLE_SYMBOLS)
+#include <cxxabi.h>
+#include <stdlib.h> // for free()
+#endif // MOZ_DEMANGLE_SYMBOLS
+
+void DemangleSymbol(const char * aSymbol,
+ char * aBuffer,
+ int aBufLen)
+{
+ aBuffer[0] = '\0';
+
+#if defined(MOZ_DEMANGLE_SYMBOLS)
+ /* See demangle.h in the gcc source for the voodoo */
+ char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
+
+ if (demangled)
+ {
+ strncpy(aBuffer,demangled,aBufLen);
+ free(demangled);
+ }
+#endif // MOZ_DEMANGLE_SYMBOLS
+}
+
+
+#if defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) // i386 or PPC Linux stackwalking code
+
+#include <setjmp.h>
+//
+
+void DumpStackToFile(FILE* aStream)
+{
+ jmp_buf jb;
+ setjmp(jb);
+
+ // Stack walking code courtesy Kipp's "leaky".
+
+ // Get the frame pointer out of the jmp_buf
+ void **bp = (void**)
+#if defined(__i386)
+ (jb[0].__jmpbuf[JB_BP]);
+#elif defined(PPC)
+ (jb[0].__jmpbuf[JB_GPR1]);
+#endif
+
+ int skip = 2;
+ for ( ; (void**)*bp > bp; bp = (void**)*bp) {
+ void *pc = *(bp+1);
+ if (--skip <= 0) {
+ Dl_info info;
+ int ok = dladdr(pc, &info);
+ if (!ok) {
+ fprintf(aStream, "UNKNOWN %p\n", pc);
+ continue;
+ }
+
+ PRUint32 foff = (char*)pc - (char*)info.dli_fbase;
+
+ const char * symbol = info.dli_sname;
+ int len;
+ if (!symbol || !(len = strlen(symbol))) {
+ fprintf(aStream, "UNKNOWN [%s +0x%08X]\n",
+ info.dli_fname, foff);
+ continue;
+ }
+
+ char demangled[4096] = "\0";
+
+ DemangleSymbol(symbol, demangled, sizeof(demangled));
+
+ if (strlen(demangled)) {
+ symbol = demangled;
+ len = strlen(symbol);
+ }
+
+ PRUint32 off = (char*)pc - (char*)info.dli_saddr;
+ fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n",
+ symbol, off, info.dli_fname, foff);
+ }
+ }
+}
+
+#elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))
+
+/*
+ * Stack walking code for Solaris courtesy of Bart Smaalder's "memtrak".
+ */
+
+#include <synch.h>
+#include <ucontext.h>
+#include <sys/frame.h>
+#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 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 );
+static void cs_operate ( void (*operate_func)(void *, void *),
+ void * usrarg, FILE * aStream );
+
+#ifndef STACK_BIAS
+#define STACK_BIAS 0
+#endif /*STACK_BIAS*/
+
+#define LOGSIZE 4096
+
+/* type of demangling function */
+typedef int demf_t(const char *, char *, size_t);
+
+static demf_t *demf;
+
+static int initialized = 0;
+
+#if defined(sparc) || defined(__sparc)
+#define FRAME_PTR_REGISTER REG_SP
+#endif
+
+#if defined(i386) || defined(__i386)
+#define FRAME_PTR_REGISTER EBP
+#endif
+
+struct bucket {
+ void * pc;
+ int index;
+ struct bucket * next;
+};
+
+struct mybuf {
+ char * buffer;
+ int chars_left;
+};
+
+
+static void myinit();
+
+#pragma init (myinit)
+
+static void
+myinit()
+{
+
+ if (! initialized) {
+#ifndef __GNUC__
+ void *handle;
+ const char *libdem = "libdemangle.so.1";
+
+ /* load libdemangle if we can and need to (only try this once) */
+ if ((handle = dlopen(libdem, RTLD_LAZY)) != NULL) {
+ demf = (demf_t *)dlsym(handle,
+ "cplus_demangle"); /*lint !e611 */
+ /*
+ * lint override above is to prevent lint from
+ * complaining about "suspicious cast".
+ */
+ }
+#endif /*__GNUC__*/
+ }
+ initialized = 1;
+}
+
+
+static int
+write_address_file(void * pc, FILE* aStream)
+{
+ static struct bucket table[2048];
+ static mutex_t lock;
+ struct bucket * ptr;
+
+ unsigned int val = NS_PTR_TO_INT32(pc);
+
+ ptr = table + ((val >> 2)&2047);
+
+ mutex_lock(&lock);
+ while (ptr->next) {
+ if (ptr->next->pc == pc)
+ break;
+ ptr = ptr->next;
+ }
+
+ if (ptr->next) {
+ mutex_unlock(&lock);
+ return (ptr->next->index);
+ } else {
+ char buffer[4096], dembuff[4096];
+ Dl_info info;
+ const char *func = "??", *lib = "??";
+
+ ptr->next = newbucket(pc);
+ mutex_unlock(&lock);
+
+ if (dladdr(pc, & info)) {
+ if (info.dli_fname)
+ lib = info.dli_fname;
+ if (info.dli_sname)
+ func = info.dli_sname;
+ }
+
+#ifdef __GNUC__
+ DemangleSymbol(func, dembuff, sizeof(dembuff));
+#else
+ if (!demf || demf(func, dembuff, sizeof (dembuff)))
+ dembuff[0] = 0;
+#endif /*__GNUC__*/
+ 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);
+ }
+}
+
+
+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);
+}
+
+
+static struct bucket *
+newbucket(void * pc)
+{
+ struct bucket * ptr = (struct bucket *) malloc(sizeof (*ptr));
+ static int index; /* protected by lock in caller */
+
+ ptr->index = index++;
+ ptr->next = NULL;
+ ptr->pc = pc;
+ return (ptr);
+}
+
+
+static struct frame *
+csgetframeptr()
+{
+ ucontext_t u;
+ struct frame *fp;
+
+ (void) getcontext(&u);
+
+ fp = (struct frame *)
+ ((char *)u.uc_mcontext.gregs[FRAME_PTR_REGISTER] +
+ STACK_BIAS);
+
+ /* make sure to return parents frame pointer.... */
+
+ return ((struct frame *)((ulong_t)fp->fr_savfp + STACK_BIAS));
+}
+
+
+static void
+cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *),
+ void *usrarg, FILE * aStream)
+{
+
+ while (fp != 0 && fp->fr_savpc != 0) {
+
+ if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0)
+ break;
+ /*
+ * watch out - libthread stacks look funny at the top
+ * so they may not have their STACK_BIAS set
+ */
+
+ fp = (struct frame *)((ulong_t)fp->fr_savfp +
+ (fp->fr_savfp?(ulong_t)STACK_BIAS:0));
+ }
+}
+
+
+static void
+cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream)
+{
+ cswalkstack(csgetframeptr(), operate_func, usrarg, aStream);
+}
+
+void DumpStackToFile(FILE* aStream)
+{
+ char buffer[LOGSIZE];
+ struct mybuf mybuf;
+
+ if (!initialized)
+ myinit();
+
+ mybuf.chars_left = LOGSIZE - strlen(buffer)-1;
+ mybuf.buffer = buffer;
+ cs_operate(load_address, &mybuf, aStream);
+}
+#endif