~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/xpcom/base/nsDebugImpl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/*
 
3
 * The contents of this file are subject to the Netscape Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/NPL/
 
7
 *
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 *
 
13
 * The Original Code is mozilla.org code.
 
14
 *
 
15
 * The Initial Developer of the Original Code is Netscape
 
16
 * Communications Corporation.  Portions created by Netscape are
 
17
 * Copyright (C) 1998 Netscape Communications Corporation. All
 
18
 * Rights Reserved.
 
19
 *
 
20
 * Contributor(s): 
 
21
 *   IBM Corp.
 
22
 *   Henry Sobotka
 
23
 */
 
24
 
 
25
#include "nsDebugImpl.h"
 
26
#include "nsDebug.h"
 
27
#include "prprf.h"
 
28
#include "prlog.h"
 
29
#include "prinit.h"
 
30
#include "plstr.h"
 
31
#include "nsError.h"
 
32
#include "prerror.h"
 
33
#include "prerr.h"
 
34
 
 
35
#if defined(XP_BEOS)
 
36
/* For DEBUGGER macros */
 
37
#include <Debug.h>
 
38
#endif
 
39
 
 
40
#if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS)
 
41
/* for abort() and getenv() */
 
42
#include <stdlib.h>
 
43
#endif
 
44
 
 
45
#if defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT)
 
46
#include <signal.h>
 
47
/* for nsTraceRefcnt::WalkTheStack() */
 
48
#include "nsISupportsUtils.h"
 
49
#include "nsTraceRefcntImpl.h"
 
50
 
 
51
#if defined(__GNUC__) && defined(__i386)
 
52
#  define DebugBreak() { asm("int $3"); }
 
53
#else
 
54
#  define DebugBreak()
 
55
#endif
 
56
#endif
 
57
 
 
58
#if defined(XP_OS2)
 
59
  /* Added definitions for DebugBreak() for 2 different OS/2 compilers.  Doing
 
60
   * the int3 on purpose so that a developer can step over the
 
61
   * instruction if so desired.  Not always possible if trapping due to exception
 
62
   * handling IBM-AKR
 
63
   */
 
64
  #define INCL_WINDIALOGS  // need for WinMessageBox
 
65
  #include <os2.h>
 
66
  #include <string.h>
 
67
  
 
68
  #if defined(DEBUG)
 
69
    #define DebugBreak() { asm("int $3"); }
 
70
  #else
 
71
    #define DebugBreak()
 
72
  #endif /* DEBUG */
 
73
#endif /* XP_OS2 */
 
74
 
 
75
#if defined(_WIN32)
 
76
#include <windows.h>
 
77
#include <signal.h>
 
78
#elif defined(XP_MAC)
 
79
   #define TEMP_MAC_HACK
 
80
   
 
81
   //------------------------
 
82
   #ifdef TEMP_MAC_HACK
 
83
           #include <MacTypes.h>
 
84
           #include <Processes.h>
 
85
           #include <string.h>
 
86
 
 
87
           // TEMPORARY UNTIL WE HAVE MACINTOSH ENVIRONMENT VARIABLES THAT CAN TURN ON
 
88
           // LOGGING ON MACINTOSH
 
89
           // At this moment, NSPR's logging is a no-op on Macintosh.
 
90
 
 
91
           #include <stdarg.h>
 
92
           #include <stdio.h>
 
93
         
 
94
           #undef PR_LOG
 
95
           #undef PR_LogFlush
 
96
           #define PR_LOG(module,level,args) dprintf args
 
97
           #define PR_LogFlush()
 
98
           static void dprintf(const char *format, ...)
 
99
           {
 
100
              va_list ap;
 
101
              Str255 buffer;
 
102
              
 
103
              va_start(ap, format);
 
104
              buffer[0] = std::vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap);
 
105
              va_end(ap);
 
106
              if (PL_strcasestr((char *)&buffer[1], "warning"))
 
107
                      printf("ļæ½ļæ½ļæ½%s\n", (char*)buffer + 1);
 
108
                  else
 
109
                      DebugStr(buffer);
 
110
           }
 
111
   #endif // TEMP_MAC_HACK
 
112
   //------------------------
 
113
#elif defined(XP_UNIX)
 
114
#include<stdlib.h>
 
115
#endif
 
116
 
 
117
/*
 
118
 * Determine if debugger is present in windows.
 
119
 */
 
120
#if defined (_WIN32)
 
121
 
 
122
typedef WINBASEAPI BOOL (WINAPI* LPFNISDEBUGGERPRESENT)();
 
123
PRBool InDebugger()
 
124
{
 
125
   PRBool fReturn = PR_FALSE;
 
126
   LPFNISDEBUGGERPRESENT lpfnIsDebuggerPresent = NULL;
 
127
   HINSTANCE hKernel = LoadLibrary("Kernel32.dll");
 
128
 
 
129
   if(hKernel)
 
130
      {
 
131
      lpfnIsDebuggerPresent = 
 
132
         (LPFNISDEBUGGERPRESENT)GetProcAddress(hKernel, "IsDebuggerPresent");
 
133
      if(lpfnIsDebuggerPresent)
 
134
         {
 
135
         fReturn = (*lpfnIsDebuggerPresent)();
 
136
         }
 
137
      FreeLibrary(hKernel);
 
138
      }
 
139
 
 
140
   return fReturn;
 
141
}
 
142
 
 
143
#endif /* WIN32*/
 
144
 
 
145
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDebugImpl, nsIDebug)
 
146
 
 
147
nsDebugImpl::nsDebugImpl()
 
148
{
 
149
}
 
150
 
 
151
/**
 
152
 * Implementation of the nsDebug methods. Note that this code is
 
153
 * always compiled in, in case some other module that uses it is
 
154
 * compiled with debugging even if this library is not.
 
155
 */
 
156
static PRLogModuleInfo* gDebugLog;
 
157
 
 
158
static void InitLog(void)
 
159
{
 
160
  if (0 == gDebugLog) {
 
161
    gDebugLog = PR_NewLogModule("nsDebug");
 
162
    gDebugLog->level = PR_LOG_DEBUG;
 
163
  }
 
164
}
 
165
 
 
166
 
 
167
 
 
168
NS_IMETHODIMP
 
169
nsDebugImpl::Assertion(const char *aStr, const char *aExpr, const char *aFile, PRInt32 aLine)
 
170
{
 
171
   InitLog();
 
172
 
 
173
   char buf[1000];
 
174
   PR_snprintf(buf, sizeof(buf),
 
175
              "###!!! ASSERTION: %s: '%s', file %s, line %d",
 
176
              aStr, aExpr, aFile, aLine);
 
177
 
 
178
   // Write out the assertion message to the debug log
 
179
   PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf));
 
180
   PR_LogFlush();
 
181
 
 
182
   // And write it out to the stderr
 
183
   fprintf(stderr, "%s\n", buf);
 
184
   fflush(stderr);
 
185
 
 
186
#if defined(_WIN32)
 
187
   char* assertBehavior = getenv("XPCOM_DEBUG_BREAK");
 
188
   if (assertBehavior && strcmp(assertBehavior, "warn") == 0)
 
189
     return NS_OK;
 
190
 
 
191
   if(!InDebugger())
 
192
      {
 
193
      DWORD code = IDRETRY;
 
194
 
 
195
      /* Create the debug dialog out of process to avoid the crashes caused by 
 
196
       * Windows events leaking into our event loop from an in process dialog.
 
197
       * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg).
 
198
       * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792
 
199
       */
 
200
      PROCESS_INFORMATION pi;
 
201
      STARTUPINFO si;
 
202
      char executable[MAX_PATH];
 
203
      char* pName;
 
204
 
 
205
      memset(&pi, 0, sizeof(pi));
 
206
 
 
207
      memset(&si, 0, sizeof(si));
 
208
      si.cb          = sizeof(si);
 
209
      si.wShowWindow = SW_SHOW;
 
210
 
 
211
      if(GetModuleFileName(GetModuleHandle("xpcom.dll"), executable, MAX_PATH) &&
 
212
         NULL != (pName = strrchr(executable, '\\')) &&
 
213
         NULL != strcpy(pName+1, "windbgdlg.exe") &&
 
214
#ifdef DEBUG_jband
 
215
         (printf("Launching %s\n", executable), PR_TRUE) &&
 
216
#endif         
 
217
         CreateProcess(executable, buf, NULL, NULL, PR_FALSE,
 
218
                       DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
 
219
                       NULL, NULL, &si, &pi) &&
 
220
         WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, INFINITE) &&
 
221
         GetExitCodeProcess(pi.hProcess, &code))
 
222
      {
 
223
        CloseHandle(pi.hProcess);
 
224
      }                         
 
225
 
 
226
      switch(code)
 
227
         {
 
228
         case IDABORT:
 
229
            //This should exit us
 
230
            raise(SIGABRT);
 
231
            //If we are ignored exit this way..
 
232
            _exit(3);
 
233
            break;
 
234
         
 
235
         case IDIGNORE:
 
236
            return NS_OK;
 
237
            // Fall Through
 
238
         }
 
239
      }
 
240
#endif
 
241
 
 
242
#if defined(XP_OS2)
 
243
   char* assertBehavior = getenv("XPCOM_DEBUG_BREAK");
 
244
   if (assertBehavior && strcmp(assertBehavior, "warn") == 0)
 
245
     return NS_OK;
 
246
 
 
247
      char msg[1200];
 
248
      PR_snprintf(msg, sizeof(msg),
 
249
                "%s\n\nClick Cancel to Debug Application.\n"
 
250
                "Click Enter to continue running the Application.", buf);
 
251
      ULONG code = MBID_ERROR;
 
252
      code = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, msg, 
 
253
                           "nsDebug::Assertion", 0,
 
254
                           MB_ERROR | MB_ENTERCANCEL);
 
255
 
 
256
      /* It is possible that we are executing on a thread that doesn't have a
 
257
       * message queue.  In that case, the message won't appear, and code will
 
258
       * be 0xFFFF.  We'll give the user a chance to debug it by calling
 
259
       * Break()
 
260
       * Actually, that's a really bad idea since this happens a lot with threadsafe
 
261
       * assertions and since it means that you can't actually run the debug build
 
262
       * outside a debugger without it crashing constantly.
 
263
       */
 
264
      if(( code == MBID_ENTER ) || (code == MBID_ERROR))
 
265
      {
 
266
         return NS_OK;
 
267
         // If Retry, Fall Through
 
268
      }
 
269
#endif
 
270
 
 
271
      Break(aFile, aLine);
 
272
      return NS_OK;
 
273
}
 
274
 
 
275
NS_IMETHODIMP 
 
276
nsDebugImpl::Break(const char *aFile, PRInt32 aLine)
 
277
{
 
278
#ifndef TEMP_MAC_HACK
 
279
  // Write out the assertion message to the debug log
 
280
   InitLog();
 
281
 
 
282
   PR_LOG(gDebugLog, PR_LOG_ERROR, 
 
283
         ("###!!! Break: at file %s, line %d", aFile, aLine));
 
284
   PR_LogFlush();
 
285
 
 
286
  fprintf(stderr, "Break: at file %s, line %d\n",aFile, aLine);  fflush(stderr);
 
287
  fflush(stderr);
 
288
 
 
289
#if defined(_WIN32)
 
290
#ifdef _M_IX86
 
291
   ::DebugBreak();
 
292
#endif
 
293
#elif defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT)
 
294
    fprintf(stderr, "\07");
 
295
 
 
296
    char *assertBehavior = getenv("XPCOM_DEBUG_BREAK");
 
297
 
 
298
    if (!assertBehavior) {
 
299
 
 
300
      // the default; nothing else to do
 
301
      ;
 
302
 
 
303
    } else if ( strcmp(assertBehavior, "suspend")== 0 ) {
 
304
 
 
305
      // the suspend case is first because we wanna send the signal before 
 
306
      // other threads have had a chance to get too far from the state that
 
307
      // caused this assertion (in case they happen to have been involved).
 
308
      //
 
309
      fprintf(stderr, "Suspending process; attach with the debugger.\n");
 
310
      kill(0, SIGSTOP);
 
311
 
 
312
    } else if ( strcmp(assertBehavior, "warn")==0 ) {
 
313
      
 
314
      // same as default; nothing else to do (see "suspend" case comment for
 
315
      // why this compare isn't done as part of the default case)
 
316
      //
 
317
      ;
 
318
 
 
319
    } 
 
320
    else if ( strcmp(assertBehavior,"stack")==0 ) {
 
321
 
 
322
      // walk the stack
 
323
      //
 
324
      nsTraceRefcntImpl::WalkTheStack(stderr);
 
325
    } 
 
326
    else if ( strcmp(assertBehavior,"abort")==0 ) {
 
327
 
 
328
      // same as UNIX_CRASH_ON_ASSERT
 
329
      //
 
330
      Abort(aFile, aLine);
 
331
 
 
332
    } else if ( strcmp(assertBehavior,"trap")==0 ) {
 
333
 
 
334
      DebugBreak();
 
335
 
 
336
    } else {
 
337
 
 
338
      fprintf(stderr, "unrecognized value of XPCOM_DEBUG_BREAK env var!\n");
 
339
 
 
340
    }    
 
341
    fflush(stderr); // this shouldn't really be necessary, i don't think,
 
342
                    // but maybe there's some lame stdio that buffers stderr
 
343
 
 
344
#elif defined(XP_BEOS)
 
345
  {
 
346
#ifdef UNIX_CRASH_ON_ASSERT
 
347
        char buf[2000];
 
348
        sprintf(buf, "Break: at file %s, line %d", aFile, aLine);
 
349
        DEBUGGER(buf);
 
350
#endif
 
351
  }
 
352
#else
 
353
  Abort(aFile, aLine);
 
354
#endif
 
355
#endif // TEMP_MAC_HACK
 
356
  return NS_OK;
 
357
}
 
358
 
 
359
NS_IMETHODIMP 
 
360
nsDebugImpl::Abort(const char *aFile, PRInt32 aLine)
 
361
{
 
362
  InitLog();
 
363
 
 
364
   PR_LOG(gDebugLog, PR_LOG_ERROR, 
 
365
         ("###!!! Abort: at file %s, line %d", aFile, aLine));
 
366
   PR_LogFlush();
 
367
   fprintf(stderr, "\07 Abort\n");  fflush(stderr);
 
368
   fflush(stderr);
 
369
 
 
370
#if defined(_WIN32)
 
371
#ifdef _M_IX86
 
372
  long* __p = (long*) 0x7;
 
373
  *__p = 0x7;
 
374
#else /* _M_ALPHA */
 
375
  PR_Abort();
 
376
#endif
 
377
#elif defined(XP_MAC)
 
378
  ExitToShell();
 
379
#elif defined(XP_UNIX)
 
380
  PR_Abort();
 
381
#elif defined(XP_OS2)
 
382
  DebugBreak();
 
383
  return NS_OK;
 
384
#elif defined(XP_BEOS)
 
385
  {
 
386
#ifndef DEBUG_cls
 
387
        char buf[2000];
 
388
        sprintf(buf, "Abort: at file %s, line %d", aFile, aLine);
 
389
        DEBUGGER(buf);
 
390
#endif
 
391
  } 
 
392
#endif
 
393
  return NS_OK;
 
394
}
 
395
 
 
396
NS_IMETHODIMP 
 
397
nsDebugImpl::Warning(const char* aMessage,
 
398
                     const char* aFile, PRIntn aLine)
 
399
{
 
400
  InitLog();
 
401
 
 
402
  char buf[1000];
 
403
  PR_snprintf(buf, sizeof(buf),
 
404
              "WARNING: %s, file %s, line %d",
 
405
              aMessage, aFile, aLine);
 
406
 
 
407
  // Write out the warning message to the debug log
 
408
  PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf));
 
409
 
 
410
  // And write it out to the stdout
 
411
  fprintf(stderr, "%s\n", buf);
 
412
  fflush(stderr);
 
413
  return NS_OK;
 
414
}
 
415
 
 
416
NS_METHOD
 
417
nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
 
418
{
 
419
  *aInstancePtr = nsnull;
 
420
  nsIDebug* debug = new nsDebugImpl();
 
421
  if (!debug)
 
422
    return NS_ERROR_OUT_OF_MEMORY;
 
423
  
 
424
  nsresult rv = debug->QueryInterface(aIID, aInstancePtr);
 
425
  if (NS_FAILED(rv)) {
 
426
    delete debug;
 
427
  }
 
428
  
 
429
  return rv;
 
430
}
 
431
 
 
432
////////////////////////////////////////////////////////////////////////////////
 
433
 
 
434
NS_COM nsresult
 
435
NS_ErrorAccordingToNSPR()
 
436
{
 
437
    PRErrorCode err = PR_GetError();
 
438
    switch (err) {
 
439
      case PR_OUT_OF_MEMORY_ERROR:              return NS_ERROR_OUT_OF_MEMORY;
 
440
      case PR_WOULD_BLOCK_ERROR:                return NS_BASE_STREAM_WOULD_BLOCK;
 
441
      case PR_FILE_NOT_FOUND_ERROR:             return NS_ERROR_FILE_NOT_FOUND;
 
442
      case PR_READ_ONLY_FILESYSTEM_ERROR:       return NS_ERROR_FILE_READ_ONLY;
 
443
      case PR_NOT_DIRECTORY_ERROR:              return NS_ERROR_FILE_NOT_DIRECTORY;
 
444
      case PR_IS_DIRECTORY_ERROR:               return NS_ERROR_FILE_IS_DIRECTORY;
 
445
      case PR_LOOP_ERROR:                       return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK;
 
446
      case PR_FILE_EXISTS_ERROR:                return NS_ERROR_FILE_ALREADY_EXISTS;
 
447
      case PR_FILE_IS_LOCKED_ERROR:             return NS_ERROR_FILE_IS_LOCKED;
 
448
      case PR_FILE_TOO_BIG_ERROR:               return NS_ERROR_FILE_TOO_BIG;
 
449
      case PR_NO_DEVICE_SPACE_ERROR:            return NS_ERROR_FILE_NO_DEVICE_SPACE;
 
450
      case PR_NAME_TOO_LONG_ERROR:              return NS_ERROR_FILE_NAME_TOO_LONG;
 
451
      case PR_DIRECTORY_NOT_EMPTY_ERROR:        return NS_ERROR_FILE_DIR_NOT_EMPTY;
 
452
      case PR_NO_ACCESS_RIGHTS_ERROR:           return NS_ERROR_FILE_ACCESS_DENIED;
 
453
      default:                                  return NS_ERROR_FAILURE;
 
454
    }
 
455
}
 
456
 
 
457
////////////////////////////////////////////////////////////////////////////////
 
458