1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
25 * Benjamin Smedberg <benjamin@smedbergs.us>
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.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsDebugImpl.h"
53 /* For DEBUGGER macros */
57 #if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS)
58 /* for abort() and getenv() */
62 #include "nsTraceRefcntImpl.h"
63 #include "nsISupportsUtils.h"
70 Abort(const char *aMsg
);
73 Break(const char *aMsg
);
76 # define INCL_WINDIALOGS // need for WinMessageBox
84 #include <malloc.h> // for _alloca
85 #elif defined(XP_UNIX)
90 * Determine if debugger is present in windows.
94 typedef WINBASEAPI
BOOL (WINAPI
* LPFNISDEBUGGERPRESENT
)();
98 PRBool fReturn
= PR_FALSE
;
99 LPFNISDEBUGGERPRESENT lpfnIsDebuggerPresent
= NULL
;
100 HINSTANCE hKernel
= LoadLibrary("Kernel32.dll");
104 lpfnIsDebuggerPresent
=
105 (LPFNISDEBUGGERPRESENT
)GetProcAddress(hKernel
, "IsDebuggerPresent");
106 if(lpfnIsDebuggerPresent
)
108 fReturn
= (*lpfnIsDebuggerPresent
)();
110 FreeLibrary(hKernel
);
121 NS_IMPL_QUERY_INTERFACE1(nsDebugImpl
, nsIDebug
)
123 NS_IMETHODIMP_(nsrefcnt
)
124 nsDebugImpl::AddRef()
129 NS_IMETHODIMP_(nsrefcnt
)
130 nsDebugImpl::Release()
136 nsDebugImpl::Assertion(const char *aStr
, const char *aExpr
,
137 const char *aFile
, PRInt32 aLine
)
139 NS_DebugBreak(NS_DEBUG_ASSERTION
, aStr
, aExpr
, aFile
, aLine
);
144 nsDebugImpl::Warning(const char *aStr
, const char *aFile
, PRInt32 aLine
)
146 NS_DebugBreak(NS_DEBUG_WARNING
, aStr
, nsnull
, aFile
, aLine
);
151 nsDebugImpl::Break(const char *aFile
, PRInt32 aLine
)
153 NS_DebugBreak(NS_DEBUG_BREAK
, nsnull
, nsnull
, aFile
, aLine
);
158 nsDebugImpl::Abort(const char *aFile
, PRInt32 aLine
)
160 NS_DebugBreak(NS_DEBUG_ABORT
, nsnull
, nsnull
, aFile
, aLine
);
165 * Implementation of the nsDebug methods. Note that this code is
166 * always compiled in, in case some other module that uses it is
167 * compiled with debugging even if this library is not.
169 static PRLogModuleInfo
* gDebugLog
;
171 static void InitLog(void)
173 if (0 == gDebugLog
) {
174 gDebugLog
= PR_NewLogModule("nsDebug");
175 gDebugLog
->level
= PR_LOG_DEBUG
;
179 enum nsAssertBehavior
{
180 NS_ASSERT_UNINITIALIZED
,
186 NS_ASSERT_STACK_AND_ABORT
189 static nsAssertBehavior
GetAssertBehavior()
191 static nsAssertBehavior gAssertBehavior
= NS_ASSERT_UNINITIALIZED
;
192 if (gAssertBehavior
!= NS_ASSERT_UNINITIALIZED
)
193 return gAssertBehavior
;
195 #if defined(XP_WIN) || defined(XP_OS2)
196 gAssertBehavior
= NS_ASSERT_TRAP
;
198 gAssertBehavior
= NS_ASSERT_WARN
;
201 const char *assertString
= PR_GetEnv("XPCOM_DEBUG_BREAK");
202 if (!assertString
|| !*assertString
)
203 return gAssertBehavior
;
205 if (!strcmp(assertString
, "warn"))
206 return gAssertBehavior
= NS_ASSERT_WARN
;
208 if (!strcmp(assertString
, "suspend"))
209 return gAssertBehavior
= NS_ASSERT_SUSPEND
;
211 if (!strcmp(assertString
, "stack"))
212 return gAssertBehavior
= NS_ASSERT_STACK
;
214 if (!strcmp(assertString
, "abort"))
215 return gAssertBehavior
= NS_ASSERT_ABORT
;
217 if (!strcmp(assertString
, "trap") || !strcmp(assertString
, "break"))
218 return gAssertBehavior
= NS_ASSERT_TRAP
;
220 if (!strcmp(assertString
, "stack-and-abort"))
221 return gAssertBehavior
= NS_ASSERT_STACK_AND_ABORT
;
223 fprintf(stderr
, "Unrecognized value of XPCOM_DEBUG_BREAK\n");
224 return gAssertBehavior
;
229 FixedBuffer() : curlen(0) { buffer
[0] = '\0'; }
236 StuffFixedBuffer(void *closure
, const char *buf
, PRUint32 len
)
241 FixedBuffer
*fb
= (FixedBuffer
*) closure
;
243 // strip the trailing null, we add it again later
244 if (buf
[len
- 1] == '\0')
247 if (fb
->curlen
+ len
>= sizeof(fb
->buffer
))
248 len
= sizeof(fb
->buffer
) - fb
->curlen
- 1;
251 memcpy(fb
->buffer
+ fb
->curlen
, buf
, len
);
253 fb
->buffer
[fb
->curlen
] = '\0';
259 EXPORT_XPCOM_API(void)
260 NS_DebugBreak(PRUint32 aSeverity
, const char *aStr
, const char *aExpr
,
261 const char *aFile
, PRInt32 aLine
)
266 PRLogModuleLevel ll
= PR_LOG_WARNING
;
267 const char *sevString
= "WARNING";
270 case NS_DEBUG_ASSERTION
:
271 sevString
= "###!!! ASSERTION";
276 sevString
= "###!!! BREAK";
281 sevString
= "###!!! ABORT";
286 aSeverity
= NS_DEBUG_WARNING
;
289 PR_sxprintf(StuffFixedBuffer
, &buf
, "%s: ", sevString
);
292 PR_sxprintf(StuffFixedBuffer
, &buf
, "%s: ", aStr
);
295 PR_sxprintf(StuffFixedBuffer
, &buf
, "'%s', ", aExpr
);
298 PR_sxprintf(StuffFixedBuffer
, &buf
, "file %s, ", aFile
);
301 PR_sxprintf(StuffFixedBuffer
, &buf
, "line %d", aLine
);
303 // Write out the message to the debug log
304 PR_LOG(gDebugLog
, ll
, ("%s", buf
.buffer
));
307 // errors on platforms without a debugdlg ring a bell on stderr
308 #if !defined(XP_WIN) && !defined(XP_OS2)
309 if (ll
!= PR_LOG_WARNING
)
310 fprintf(stderr
, "\07");
313 // Write the message to stderr
314 fprintf(stderr
, "%s\n", buf
.buffer
);
318 case NS_DEBUG_WARNING
:
330 // Now we deal with assertions
332 switch (GetAssertBehavior()) {
336 case NS_ASSERT_SUSPEND
:
338 fprintf(stderr
, "Suspending process; attach with the debugger.\n");
345 case NS_ASSERT_STACK
:
346 nsTraceRefcntImpl::WalkTheStack(stderr
);
349 case NS_ASSERT_STACK_AND_ABORT
:
350 nsTraceRefcntImpl::WalkTheStack(stderr
);
351 // Fall through to abort
353 case NS_ASSERT_ABORT
:
363 Abort(const char *aMsg
)
366 //This should exit us
368 //If we are ignored exit this way..
370 #elif defined(XP_UNIX)
372 #elif defined(XP_BEOS)
379 // Don't know how to abort on this platform! call Break() instead
384 // Abort() calls this function, don't call it!
386 Break(const char *aMsg
)
389 #ifndef WINCE // we really just want to crash for now
390 static int ignoreDebugger
;
391 if (!ignoreDebugger
) {
392 const char *shouldIgnoreDebugger
= getenv("XPCOM_DEBUG_DLG");
393 ignoreDebugger
= 1 + (shouldIgnoreDebugger
&& !strcmp(shouldIgnoreDebugger
, "1"));
395 if((ignoreDebugger
== 2) || !InDebugger()) {
396 DWORD code
= IDRETRY
;
398 /* Create the debug dialog out of process to avoid the crashes caused by
399 * Windows events leaking into our event loop from an in process dialog.
400 * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg).
401 * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792
403 PROCESS_INFORMATION pi
;
405 char executable
[MAX_PATH
];
408 memset(&pi
, 0, sizeof(pi
));
410 memset(&si
, 0, sizeof(si
));
412 si
.wShowWindow
= SW_SHOW
;
414 // 2nd arg of CreateProcess is in/out
415 char *msgCopy
= (char*) _alloca(strlen(aMsg
) + 1);
416 strcpy(msgCopy
, aMsg
);
418 if(GetModuleFileName(GetModuleHandle("xpcom.dll"), executable
, MAX_PATH
) &&
419 NULL
!= (pName
= strrchr(executable
, '\\')) &&
420 NULL
!= strcpy(pName
+1, "windbgdlg.exe") &&
421 CreateProcess(executable
, msgCopy
, NULL
, NULL
, PR_FALSE
,
422 DETACHED_PROCESS
| NORMAL_PRIORITY_CLASS
,
423 NULL
, NULL
, &si
, &pi
)) {
424 WaitForSingleObject(pi
.hProcess
, INFINITE
);
425 GetExitCodeProcess(pi
.hProcess
, &code
);
426 CloseHandle(pi
.hProcess
);
427 CloseHandle(pi
.hThread
);
432 //This should exit us
434 //If we are ignored exit this way..
445 #elif defined(XP_OS2)
447 PR_snprintf(msg
, sizeof(msg
),
448 "%s\n\nClick Cancel to Debug Application.\n"
449 "Click Enter to continue running the Application.", aMsg
);
450 ULONG code
= MBID_ERROR
;
451 code
= WinMessageBox(HWND_DESKTOP
, HWND_DESKTOP
, msg
,
452 "NSGlue_Assertion", 0,
453 MB_ERROR
| MB_ENTERCANCEL
);
455 /* It is possible that we are executing on a thread that doesn't have a
456 * message queue. In that case, the message won't appear, and code will
457 * be 0xFFFF. We'll give the user a chance to debug it by calling
459 * Actually, that's a really bad idea since this happens a lot with threadsafe
460 * assertions and since it means that you can't actually run the debug build
461 * outside a debugger without it crashing constantly.
463 if (( code
== MBID_ENTER
) || (code
== MBID_ERROR
))
467 #elif defined(XP_BEOS)
469 #elif defined(XP_MACOSX)
470 /* Note that we put this Mac OS X test above the GNUC/x86 test because the
471 * GNUC/x86 test is also true on Intel Mac OS X and we want the PPC/x86
472 * impls to be the same.
475 #elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
478 // don't know how to break on this platform
482 static const nsDebugImpl kImpl
;
485 nsDebugImpl::Create(nsISupports
* outer
, const nsIID
& aIID
, void* *aInstancePtr
)
487 NS_ENSURE_NO_AGGREGATION(outer
);
489 return const_cast<nsDebugImpl
*>(&kImpl
)->
490 QueryInterface(aIID
, aInstancePtr
);
493 ////////////////////////////////////////////////////////////////////////////////
496 NS_ErrorAccordingToNSPR()
498 PRErrorCode err
= PR_GetError();
500 case PR_OUT_OF_MEMORY_ERROR
: return NS_ERROR_OUT_OF_MEMORY
;
501 case PR_WOULD_BLOCK_ERROR
: return NS_BASE_STREAM_WOULD_BLOCK
;
502 case PR_FILE_NOT_FOUND_ERROR
: return NS_ERROR_FILE_NOT_FOUND
;
503 case PR_READ_ONLY_FILESYSTEM_ERROR
: return NS_ERROR_FILE_READ_ONLY
;
504 case PR_NOT_DIRECTORY_ERROR
: return NS_ERROR_FILE_NOT_DIRECTORY
;
505 case PR_IS_DIRECTORY_ERROR
: return NS_ERROR_FILE_IS_DIRECTORY
;
506 case PR_LOOP_ERROR
: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK
;
507 case PR_FILE_EXISTS_ERROR
: return NS_ERROR_FILE_ALREADY_EXISTS
;
508 case PR_FILE_IS_LOCKED_ERROR
: return NS_ERROR_FILE_IS_LOCKED
;
509 case PR_FILE_TOO_BIG_ERROR
: return NS_ERROR_FILE_TOO_BIG
;
510 case PR_NO_DEVICE_SPACE_ERROR
: return NS_ERROR_FILE_NO_DEVICE_SPACE
;
511 case PR_NAME_TOO_LONG_ERROR
: return NS_ERROR_FILE_NAME_TOO_LONG
;
512 case PR_DIRECTORY_NOT_EMPTY_ERROR
: return NS_ERROR_FILE_DIR_NOT_EMPTY
;
513 case PR_NO_ACCESS_RIGHTS_ERROR
: return NS_ERROR_FILE_ACCESS_DENIED
;
514 default: return NS_ERROR_FAILURE
;
518 ////////////////////////////////////////////////////////////////////////////////