Back to index

lightning-sunbird  0.9+nobinonly
jsutil.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   IBM Corp.
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /*
00042  * PR assertion checker.
00043  */
00044 #include "jsstddef.h"
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include "jstypes.h"
00048 #include "jsutil.h"
00049 
00050 #ifdef WIN32
00051 #    include <windows.h>
00052 #endif
00053 
00054 JS_PUBLIC_API(void) JS_Assert(const char *s, const char *file, JSIntn ln)
00055 {
00056     fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
00057 #if defined(WIN32)
00058     DebugBreak();
00059     exit(3);
00060 #elif defined(XP_OS2) || (defined(__GNUC__) && defined(__i386))
00061     asm("int $3");
00062 #endif
00063     abort();
00064 }
00065 
00066 #if defined DEBUG_notme && defined XP_UNIX
00067 
00068 #define __USE_GNU 1
00069 #include <dlfcn.h>
00070 #include <string.h>
00071 #include "jshash.h"
00072 #include "jsprf.h"
00073 
00074 JSCallsite js_calltree_root = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL};
00075 
00076 static JSCallsite *
00077 CallTree(void **bp)
00078 {
00079     void **bpup, **bpdown, *pc;
00080     JSCallsite *parent, *site, **csp;
00081     Dl_info info;
00082     int ok, offset;
00083     const char *symbol;
00084     char *method;
00085 
00086     /* Reverse the stack frame list to avoid recursion. */
00087     bpup = NULL;
00088     for (;;) {
00089         bpdown = (void**) bp[0];
00090         bp[0] = (void*) bpup;
00091         if ((void**) bpdown[0] < bpdown)
00092             break;
00093         bpup = bp;
00094         bp = bpdown;
00095     }
00096 
00097     /* Reverse the stack again, finding and building a path in the tree. */
00098     parent = &js_calltree_root;
00099     do {
00100         bpup = (void**) bp[0];
00101         bp[0] = (void*) bpdown;
00102         pc = bp[1];
00103 
00104         csp = &parent->kids;
00105         while ((site = *csp) != NULL) {
00106             if (site->pc == pc) {
00107                 /* Put the most recently used site at the front of siblings. */
00108                 *csp = site->siblings;
00109                 site->siblings = parent->kids;
00110                 parent->kids = site;
00111 
00112                 /* Site already built -- go up the stack. */
00113                 goto upward;
00114             }
00115             csp = &site->siblings;
00116         }
00117 
00118         /* Check for recursion: see if pc is on our ancestor line. */
00119         for (site = parent; site; site = site->parent) {
00120             if (site->pc == pc)
00121                 goto upward;
00122         }
00123 
00124         /*
00125          * Not in tree at all: let's find our symbolic callsite info.
00126          * XXX static syms are masked by nearest lower global
00127          */
00128         info.dli_fname = info.dli_sname = NULL;
00129         ok = dladdr(pc, &info);
00130         if (ok < 0) {
00131             fprintf(stderr, "dladdr failed!\n");
00132             return NULL;
00133         }
00134 
00135 /* XXXbe sub 0x08040000? or something, see dbaron bug with tenthumbs comment */
00136         symbol = info.dli_sname;
00137         offset = (char*)pc - (char*)info.dli_fbase;
00138         method = symbol
00139                  ? strdup(symbol)
00140                  : JS_smprintf("%s+%X",
00141                                info.dli_fname ? info.dli_fname : "main",
00142                                offset);
00143         if (!method)
00144             return NULL;
00145 
00146         /* Create a new callsite record. */
00147         site = (JSCallsite *) malloc(sizeof(JSCallsite));
00148         if (!site)
00149             return NULL;
00150 
00151         /* Insert the new site into the tree. */
00152         site->pc = pc;
00153         site->name = method;
00154         site->library = info.dli_fname;
00155         site->offset = offset;
00156         site->parent = parent;
00157         site->siblings = parent->kids;
00158         parent->kids = site;
00159         site->kids = NULL;
00160 
00161       upward:
00162         parent = site;
00163         bpdown = bp;
00164         bp = bpup;
00165     } while (bp);
00166 
00167     return site;
00168 }
00169 
00170 JSCallsite *
00171 JS_Backtrace(int skip)
00172 {
00173     void **bp, **bpdown;
00174 
00175     /* Stack walking code adapted from Kipp's "leaky". */
00176 #if defined(__i386)
00177     __asm__( "movl %%ebp, %0" : "=g"(bp));
00178 #elif defined(__x86_64__)
00179     __asm__( "movq %%rbp, %0" : "=g"(bp));
00180 #else
00181     /*
00182      * It would be nice if this worked uniformly, but at least on i386 and
00183      * x86_64, it stopped working with gcc 4.1, because it points to the
00184      * end of the saved registers instead of the start.
00185      */
00186     bp = (void**) __builtin_frame_address(0);
00187 #endif
00188     while (--skip >= 0) {
00189         bpdown = (void**) *bp++;
00190         if (bpdown < bp)
00191             break;
00192         bp = bpdown;
00193     }
00194 
00195     return CallTree(bp);
00196 }
00197 
00198 #endif /* DEBUG_notme && XP_UNIX */