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"
54 #include <android/log.h>
58 /* For DEBUGGER macros */
62 #if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS)
63 /* for abort() and getenv() */
67 #include "nsTraceRefcntImpl.h"
68 #include "nsISupportsUtils.h"
79 #include "mozilla/mozalloc_abort.h"
82 Abort(const char *aMsg
);
88 Break(const char *aMsg
);
91 # define INCL_WINDIALOGS // need for WinMessageBox
99 #include <malloc.h> // for _alloca
100 #elif defined(XP_UNIX)
104 static PRInt32 gAssertionCount
= 0;
106 NS_IMPL_QUERY_INTERFACE2(nsDebugImpl
, nsIDebug
, nsIDebug2
)
108 NS_IMETHODIMP_(nsrefcnt
)
109 nsDebugImpl::AddRef()
114 NS_IMETHODIMP_(nsrefcnt
)
115 nsDebugImpl::Release()
121 nsDebugImpl::Assertion(const char *aStr
, const char *aExpr
,
122 const char *aFile
, PRInt32 aLine
)
124 NS_DebugBreak(NS_DEBUG_ASSERTION
, aStr
, aExpr
, aFile
, aLine
);
129 nsDebugImpl::Warning(const char *aStr
, const char *aFile
, PRInt32 aLine
)
131 NS_DebugBreak(NS_DEBUG_WARNING
, aStr
, nsnull
, aFile
, aLine
);
136 nsDebugImpl::Break(const char *aFile
, PRInt32 aLine
)
138 NS_DebugBreak(NS_DEBUG_BREAK
, nsnull
, nsnull
, aFile
, aLine
);
143 nsDebugImpl::Abort(const char *aFile
, PRInt32 aLine
)
145 NS_DebugBreak(NS_DEBUG_ABORT
, nsnull
, nsnull
, aFile
, aLine
);
150 nsDebugImpl::GetIsDebugBuild(PRBool
* aResult
)
161 nsDebugImpl::GetAssertionCount(PRInt32
* aResult
)
163 *aResult
= gAssertionCount
;
168 * Implementation of the nsDebug methods. Note that this code is
169 * always compiled in, in case some other module that uses it is
170 * compiled with debugging even if this library is not.
172 static PRLogModuleInfo
* gDebugLog
;
174 static void InitLog(void)
176 if (0 == gDebugLog
) {
177 gDebugLog
= PR_NewLogModule("nsDebug");
178 gDebugLog
->level
= PR_LOG_DEBUG
;
182 enum nsAssertBehavior
{
183 NS_ASSERT_UNINITIALIZED
,
189 NS_ASSERT_STACK_AND_ABORT
192 static nsAssertBehavior
GetAssertBehavior()
194 static nsAssertBehavior gAssertBehavior
= NS_ASSERT_UNINITIALIZED
;
195 if (gAssertBehavior
!= NS_ASSERT_UNINITIALIZED
)
196 return gAssertBehavior
;
198 #if defined(XP_WIN) || defined(XP_OS2)
199 gAssertBehavior
= NS_ASSERT_TRAP
;
201 gAssertBehavior
= NS_ASSERT_WARN
;
204 const char *assertString
= PR_GetEnv("XPCOM_DEBUG_BREAK");
205 if (!assertString
|| !*assertString
)
206 return gAssertBehavior
;
208 if (!strcmp(assertString
, "warn"))
209 return gAssertBehavior
= NS_ASSERT_WARN
;
211 if (!strcmp(assertString
, "suspend"))
212 return gAssertBehavior
= NS_ASSERT_SUSPEND
;
214 if (!strcmp(assertString
, "stack"))
215 return gAssertBehavior
= NS_ASSERT_STACK
;
217 if (!strcmp(assertString
, "abort"))
218 return gAssertBehavior
= NS_ASSERT_ABORT
;
220 if (!strcmp(assertString
, "trap") || !strcmp(assertString
, "break"))
221 return gAssertBehavior
= NS_ASSERT_TRAP
;
223 if (!strcmp(assertString
, "stack-and-abort"))
224 return gAssertBehavior
= NS_ASSERT_STACK_AND_ABORT
;
226 fprintf(stderr
, "Unrecognized value of XPCOM_DEBUG_BREAK\n");
227 return gAssertBehavior
;
232 FixedBuffer() : curlen(0) { buffer
[0] = '\0'; }
239 StuffFixedBuffer(void *closure
, const char *buf
, PRUint32 len
)
244 FixedBuffer
*fb
= (FixedBuffer
*) closure
;
246 // strip the trailing null, we add it again later
247 if (buf
[len
- 1] == '\0')
250 if (fb
->curlen
+ len
>= sizeof(fb
->buffer
))
251 len
= sizeof(fb
->buffer
) - fb
->curlen
- 1;
254 memcpy(fb
->buffer
+ fb
->curlen
, buf
, len
);
256 fb
->buffer
[fb
->curlen
] = '\0';
262 EXPORT_XPCOM_API(void)
263 NS_DebugBreak(PRUint32 aSeverity
, const char *aStr
, const char *aExpr
,
264 const char *aFile
, PRInt32 aLine
)
269 PRLogModuleLevel ll
= PR_LOG_WARNING
;
270 const char *sevString
= "WARNING";
273 case NS_DEBUG_ASSERTION
:
274 sevString
= "###!!! ASSERTION";
279 sevString
= "###!!! BREAK";
284 sevString
= "###!!! ABORT";
289 aSeverity
= NS_DEBUG_WARNING
;
292 PR_sxprintf(StuffFixedBuffer
, &buf
, "%s: ", sevString
);
295 PR_sxprintf(StuffFixedBuffer
, &buf
, "%s: ", aStr
);
298 PR_sxprintf(StuffFixedBuffer
, &buf
, "'%s', ", aExpr
);
301 PR_sxprintf(StuffFixedBuffer
, &buf
, "file %s, ", aFile
);
304 PR_sxprintf(StuffFixedBuffer
, &buf
, "line %d", aLine
);
306 // Write out the message to the debug log
307 PR_LOG(gDebugLog
, ll
, ("%s", buf
.buffer
));
310 // errors on platforms without a debugdlg ring a bell on stderr
311 #if !defined(XP_WIN) && !defined(XP_OS2)
312 if (ll
!= PR_LOG_WARNING
)
313 fprintf(stderr
, "\07");
317 __android_log_print(ANDROID_LOG_INFO
, "Gecko", "%s", buf
.buffer
);
320 // Write the message to stderr
321 fprintf(stderr
, "%s\n", buf
.buffer
);
325 case NS_DEBUG_WARNING
:
333 #if defined(DEBUG) && defined(_WIN32)
336 nsTraceRefcntImpl::WalkTheStack(stderr
);
341 // Now we deal with assertions
342 PR_AtomicIncrement(&gAssertionCount
);
344 switch (GetAssertBehavior()) {
348 case NS_ASSERT_SUSPEND
:
350 fprintf(stderr
, "Suspending process; attach with the debugger.\n");
357 case NS_ASSERT_STACK
:
358 nsTraceRefcntImpl::WalkTheStack(stderr
);
361 case NS_ASSERT_STACK_AND_ABORT
:
362 nsTraceRefcntImpl::WalkTheStack(stderr
);
363 // Fall through to abort
365 case NS_ASSERT_ABORT
:
370 case NS_ASSERT_UNINITIALIZED
: // Default to "trap" behavior
377 Abort(const char *aMsg
)
379 mozalloc_abort(aMsg
);
389 #elif defined(XP_OS2)
391 #elif defined(XP_BEOS)
392 #elif defined(XP_MACOSX)
394 #elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
396 #elif defined(__arm__)
398 #elif defined(SOLARIS)
399 #if defined(__i386__) || defined(__i386) || defined(__x86_64__)
405 #warning don't know how to break on this platform
409 // Abort() calls this function, don't call it!
411 Break(const char *aMsg
)
414 #ifndef WINCE // we really just want to crash for now
415 static int ignoreDebugger
;
416 if (!ignoreDebugger
) {
417 const char *shouldIgnoreDebugger
= getenv("XPCOM_DEBUG_DLG");
418 ignoreDebugger
= 1 + (shouldIgnoreDebugger
&& !strcmp(shouldIgnoreDebugger
, "1"));
420 if ((ignoreDebugger
== 2) || !::IsDebuggerPresent()) {
421 DWORD code
= IDRETRY
;
423 /* Create the debug dialog out of process to avoid the crashes caused by
424 * Windows events leaking into our event loop from an in process dialog.
425 * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg).
426 * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792
428 PROCESS_INFORMATION pi
;
430 PRUnichar executable
[MAX_PATH
];
433 memset(&pi
, 0, sizeof(pi
));
435 memset(&si
, 0, sizeof(si
));
437 si
.wShowWindow
= SW_SHOW
;
439 // 2nd arg of CreateProcess is in/out
440 PRUnichar
*msgCopy
= (PRUnichar
*) _alloca((strlen(aMsg
) + 1)*sizeof(PRUnichar
));
441 wcscpy(msgCopy
, (PRUnichar
*)NS_ConvertUTF8toUTF16(aMsg
).get());
443 if(GetModuleFileNameW(GetModuleHandleW(L
"xpcom.dll"), (LPWCH
)executable
, MAX_PATH
) &&
444 NULL
!= (pName
= wcsrchr(executable
, '\\')) &&
447 pName
+1, L
"windbgdlg.exe") &&
448 CreateProcessW((LPCWSTR
)executable
, (LPWSTR
)msgCopy
, NULL
, NULL
, PR_FALSE
,
449 DETACHED_PROCESS
| NORMAL_PRIORITY_CLASS
,
450 NULL
, NULL
, &si
, &pi
)) {
451 WaitForSingleObject(pi
.hProcess
, INFINITE
);
452 GetExitCodeProcess(pi
.hProcess
, &code
);
453 CloseHandle(pi
.hProcess
);
454 CloseHandle(pi
.hThread
);
459 //This should exit us
461 //If we are ignored exit this way..
471 #elif defined(XP_OS2)
473 PR_snprintf(msg
, sizeof(msg
),
474 "%s\n\nClick Cancel to Debug Application.\n"
475 "Click Enter to continue running the Application.", aMsg
);
476 ULONG code
= MBID_ERROR
;
477 code
= WinMessageBox(HWND_DESKTOP
, HWND_DESKTOP
, msg
,
478 "NSGlue_Assertion", 0,
479 MB_ERROR
| MB_ENTERCANCEL
);
481 /* It is possible that we are executing on a thread that doesn't have a
482 * message queue. In that case, the message won't appear, and code will
483 * be 0xFFFF. We'll give the user a chance to debug it by calling
485 * Actually, that's a really bad idea since this happens a lot with threadsafe
486 * assertions and since it means that you can't actually run the debug build
487 * outside a debugger without it crashing constantly.
489 if (( code
== MBID_ENTER
) || (code
== MBID_ERROR
))
493 #elif defined(XP_BEOS)
496 #elif defined(XP_MACOSX)
497 /* Note that we put this Mac OS X test above the GNUC/x86 test because the
498 * GNUC/x86 test is also true on Intel Mac OS X and we want the PPC/x86
499 * impls to be the same.
502 #elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
504 #elif defined(__arm__)
506 #elif defined(SOLARIS)
509 #warning don't know how to break on this platform
513 static const nsDebugImpl kImpl;
516 nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
518 NS_ENSURE_NO_AGGREGATION(outer);
520 return const_cast<nsDebugImpl*>(&kImpl)->
521 QueryInterface(aIID, aInstancePtr);
524 ////////////////////////////////////////////////////////////////////////////////
527 NS_ErrorAccordingToNSPR()
529 PRErrorCode err = PR_GetError();
531 case PR_OUT_OF_MEMORY_ERROR: return NS_ERROR_OUT_OF_MEMORY;
532 case PR_WOULD_BLOCK_ERROR: return NS_BASE_STREAM_WOULD_BLOCK;
533 case PR_FILE_NOT_FOUND_ERROR: return NS_ERROR_FILE_NOT_FOUND;
534 case PR_READ_ONLY_FILESYSTEM_ERROR: return NS_ERROR_FILE_READ_ONLY;
535 case PR_NOT_DIRECTORY_ERROR: return NS_ERROR_FILE_NOT_DIRECTORY;
536 case PR_IS_DIRECTORY_ERROR: return NS_ERROR_FILE_IS_DIRECTORY;
537 case PR_LOOP_ERROR: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK;
538 case PR_FILE_EXISTS_ERROR: return NS_ERROR_FILE_ALREADY_EXISTS;
539 case PR_FILE_IS_LOCKED_ERROR: return NS_ERROR_FILE_IS_LOCKED;
540 case PR_FILE_TOO_BIG_ERROR: return NS_ERROR_FILE_TOO_BIG;
541 case PR_NO_DEVICE_SPACE_ERROR: return NS_ERROR_FILE_NO_DEVICE_SPACE;
542 case PR_NAME_TOO_LONG_ERROR: return NS_ERROR_FILE_NAME_TOO_LONG;
543 case PR_DIRECTORY_NOT_EMPTY_ERROR: return NS_ERROR_FILE_DIR_NOT_EMPTY;
544 case PR_NO_ACCESS_RIGHTS_ERROR: return NS_ERROR_FILE_ACCESS_DENIED;
545 default: return NS_ERROR_FAILURE;
549 ////////////////////////////////////////////////////////////////////////////////
552 NS_COM PRBool sXPCOMHasLoadedNewDLLs = PR_FALSE;
555 NS_SetHasLoadedNewDLLs()
557 sXPCOMHasLoadedNewDLLs = PR_TRUE;