LCOV - code coverage report
Current view: directory - js/src - jscrashreport.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 54 25 46.3 %
Date: 2012-06-02 Functions: 14 8 57.1 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
      18                 :  * May 28, 2008.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   Mozilla Foundation
      22                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "jsapi.h"
      42                 : #include "jscntxt.h"
      43                 : #include "jscrashreport.h"
      44                 : #include "jscrashformat.h"
      45                 : 
      46                 : #include <time.h>
      47                 : 
      48                 : namespace js {
      49                 : namespace crash {
      50                 : 
      51                 : const static int stack_snapshot_max_size = 32768;
      52                 : 
      53                 : #if defined(XP_WIN)
      54                 : 
      55                 : #include <windows.h>
      56                 : 
      57                 : static bool
      58                 : GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
      59                 : {
      60                 :     /* Try to figure out how big the stack is. */
      61                 :     char dummy;
      62                 :     MEMORY_BASIC_INFORMATION info;
      63                 :     if (VirtualQuery(reinterpret_cast<LPCVOID>(&dummy), &info, sizeof(info)) == 0)
      64                 :         return false;
      65                 :     if (info.State != MEM_COMMIT)
      66                 :         return false;
      67                 : 
      68                 :     /* 256 is a fudge factor to account for the rest of GetStack's frame. */
      69                 :     uint64_t p = uint64_t(&dummy) - 256;
      70                 :     uint64_t len = stack_snapshot_max_size;
      71                 : 
      72                 :     if (p + len > uint64_t(info.BaseAddress) + info.RegionSize)
      73                 :         len = uint64_t(info.BaseAddress) + info.RegionSize - p;
      74                 : 
      75                 :     if (len > size)
      76                 :         len = size;
      77                 : 
      78                 :     *stack = p;
      79                 :     *stack_len = len;
      80                 : 
      81                 :     /* Get the register state. */
      82                 : #if defined(_MSC_VER) && JS_BITS_PER_WORD == 32
      83                 :     /* ASM version for win2k that doesn't support RtlCaptureContext */
      84                 :     uint32_t vip, vsp, vbp;
      85                 :     __asm {
      86                 :     Label:
      87                 :         mov [vbp], ebp;
      88                 :         mov [vsp], esp;
      89                 :         mov eax, [Label];
      90                 :         mov [vip], eax;
      91                 :     }
      92                 :     regs->ip = vip;
      93                 :     regs->sp = vsp;
      94                 :     regs->bp = vbp;
      95                 : #else
      96                 :     CONTEXT context;
      97                 :     RtlCaptureContext(&context);
      98                 : #if JS_BITS_PER_WORD == 32
      99                 :     regs->ip = context.Eip;
     100                 :     regs->sp = context.Esp;
     101                 :     regs->bp = context.Ebp;
     102                 : #else
     103                 :     regs->ip = context.Rip;
     104                 :     regs->sp = context.Rsp;
     105                 :     regs->bp = context.Rbp;
     106                 : #endif
     107                 : #endif
     108                 : 
     109                 :     js_memcpy(buffer, (void *)p, len);
     110                 : 
     111                 :     return true;
     112                 : }
     113                 : 
     114                 : #elif 0
     115                 : 
     116                 : #include <unistd.h>
     117                 : #include <ucontext.h>
     118                 : #include <sys/mman.h>
     119                 : 
     120                 : static bool
     121                 : GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
     122                 : {
     123                 :     /* 256 is a fudge factor to account for the rest of GetStack's frame. */
     124                 :     char dummy;
     125                 :     uint64_t p = uint64_t(&dummy) - 256;
     126                 :     uint64_t pgsz = getpagesize();
     127                 :     uint64_t len = stack_snapshot_max_size;
     128                 :     p &= ~(pgsz - 1);
     129                 : 
     130                 :     /* Try to figure out how big the stack is. */
     131                 :     while (len > 0) {
     132                 :         if (mlock((const void *)p, len) == 0) {
     133                 :             munlock((const void *)p, len);
     134                 :             break;
     135                 :         }
     136                 :         len -= pgsz;
     137                 :     }
     138                 : 
     139                 :     if (len > size)
     140                 :         len = size;
     141                 : 
     142                 :     *stack = p;
     143                 :     *stack_len = len;
     144                 : 
     145                 :     /* Get the register state. */
     146                 :     ucontext_t context;
     147                 :     if (getcontext(&context) != 0)
     148                 :         return false;
     149                 : 
     150                 : #if JS_BITS_PER_WORD == 64
     151                 :     regs->sp = (uint64_t)context.uc_mcontext.gregs[REG_RSP];
     152                 :     regs->bp = (uint64_t)context.uc_mcontext.gregs[REG_RBP];
     153                 :     regs->ip = (uint64_t)context.uc_mcontext.gregs[REG_RIP];
     154                 : #elif JS_BITS_PER_WORD == 32
     155                 :     regs->sp = (uint64_t)context.uc_mcontext.gregs[REG_ESP];
     156                 :     regs->bp = (uint64_t)context.uc_mcontext.gregs[REG_EBP];
     157                 :     regs->ip = (uint64_t)context.uc_mcontext.gregs[REG_EIP];
     158                 : #endif
     159                 : 
     160                 :     js_memcpy(buffer, (void *)p, len);
     161                 : 
     162                 :     return true;
     163                 : }
     164                 : 
     165                 : #else
     166                 : 
     167                 : static bool
     168           14736 : GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
     169                 : {
     170           14736 :     return false;
     171                 : }
     172                 : 
     173                 : #endif
     174                 : 
     175                 : class Stack : private CrashStack
     176                 : {
     177                 : public:
     178                 :     Stack(uint64_t id);
     179                 : 
     180                 :     bool snapshot();
     181                 : };
     182                 : 
     183           39740 : Stack::Stack(uint64_t id)
     184           39740 :   : CrashStack(id)
     185                 : {
     186           39740 : }
     187                 : 
     188                 : bool
     189           14736 : Stack::snapshot()
     190                 : {
     191           14736 :     snaptime = time(NULL);
     192           14736 :     return GetStack(&stack_base, &stack_len, &regs, stack, sizeof(stack));
     193                 : }
     194                 : 
     195                 : class Ring : private CrashRing
     196                 : {
     197                 : public:
     198                 :     Ring(uint64_t id);
     199                 : 
     200                 :     void push(uint64_t tag, void *data, size_t size);
     201                 : 
     202                 : private:
     203               0 :     size_t bufferSize() { return crash_buffer_size; }
     204                 :     void copyBytes(void *data, size_t size);
     205                 : };
     206                 : 
     207           19870 : Ring::Ring(uint64_t id)
     208           19870 :   : CrashRing(id)
     209                 : {
     210           19870 : }
     211                 : 
     212                 : void
     213               0 : Ring::push(uint64_t tag, void *data, size_t size)
     214                 : {
     215               0 :     uint64_t t = time(NULL);
     216                 : 
     217               0 :     copyBytes(&tag, sizeof(uint64_t));
     218               0 :     copyBytes(&t, sizeof(uint64_t));
     219               0 :     copyBytes(data, size);
     220               0 :     uint64_t mysize = size;
     221               0 :     copyBytes(&mysize, sizeof(uint64_t));
     222               0 : }
     223                 : 
     224                 : void
     225               0 : Ring::copyBytes(void *data, size_t size)
     226                 : {
     227               0 :     if (size >= bufferSize())
     228               0 :         size = bufferSize();
     229                 : 
     230               0 :     if (offset + size > bufferSize()) {
     231               0 :         size_t first = bufferSize() - offset;
     232               0 :         size_t second = size - first;
     233               0 :         js_memcpy(&buffer[offset], data, first);
     234               0 :         js_memcpy(buffer, (char *)data + first, second);
     235               0 :         offset = second;
     236                 :     } else {
     237               0 :         js_memcpy(&buffer[offset], data, size);
     238               0 :         offset += size;
     239                 :     }
     240               0 : }
     241                 : 
     242                 : static bool gInitialized;
     243                 : 
     244           19870 : static Stack gGCStack(JS_CRASH_STACK_GC);
     245           19870 : static Stack gErrorStack(JS_CRASH_STACK_ERROR);
     246           19870 : static Ring gRingBuffer(JS_CRASH_RING);
     247                 : 
     248                 : void
     249           51092 : SnapshotGCStack()
     250                 : {
     251           51092 :     if (gInitialized)
     252           14736 :         gGCStack.snapshot();
     253           51092 : }
     254                 : 
     255                 : void
     256               0 : SnapshotErrorStack()
     257                 : {
     258               0 :     if (gInitialized)
     259               0 :         gErrorStack.snapshot();
     260               0 : }
     261                 : 
     262                 : void
     263               0 : SaveCrashData(uint64_t tag, void *ptr, size_t size)
     264                 : {
     265               0 :     if (gInitialized)
     266               0 :         gRingBuffer.push(tag, ptr, size);
     267               0 : }
     268                 : 
     269                 : } /* namespace crash */
     270                 : } /* namespace js */
     271                 : 
     272                 : using namespace js;
     273                 : using namespace js::crash;
     274                 : 
     275                 : JS_PUBLIC_API(void)
     276            1404 : JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
     277                 : {
     278                 : #ifdef JS_CRASH_DIAGNOSTICS
     279            1404 :     if (!gInitialized) {
     280            1404 :         gInitialized = true;
     281            1404 :         (*callback)(&gGCStack, sizeof(gGCStack));
     282            1404 :         (*callback)(&gErrorStack, sizeof(gErrorStack));
     283            1404 :         (*callback)(&gRingBuffer, sizeof(gRingBuffer));
     284                 :     }
     285                 : #endif
     286           61014 : }
     287                 : 

Generated by: LCOV version 1.7