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"
75 Abort(const char *aMsg
);
78 Break(const char *aMsg
);
81 # define INCL_WINDIALOGS // need for WinMessageBox
89 #include <malloc.h> // for _alloca
90 #elif defined(XP_UNIX)
94 NS_IMPL_QUERY_INTERFACE1(nsDebugImpl
, nsIDebug
)
96 NS_IMETHODIMP_(nsrefcnt
)
102 NS_IMETHODIMP_(nsrefcnt
)
103 nsDebugImpl::Release()
109 nsDebugImpl::Assertion(const char *aStr
, const char *aExpr
,
110 const char *aFile
, PRInt32 aLine
)
112 NS_DebugBreak(NS_DEBUG_ASSERTION
, aStr
, aExpr
, aFile
, aLine
);
117 nsDebugImpl::Warning(const char *aStr
, const char *aFile
, PRInt32 aLine
)
119 NS_DebugBreak(NS_DEBUG_WARNING
, aStr
, nsnull
, aFile
, aLine
);
124 nsDebugImpl::Break(const char *aFile
, PRInt32 aLine
)
126 NS_DebugBreak(NS_DEBUG_BREAK
, nsnull
, nsnull
, aFile
, aLine
);
131 nsDebugImpl::Abort(const char *aFile
, PRInt32 aLine
)
133 NS_DebugBreak(NS_DEBUG_ABORT
, nsnull
, nsnull
, aFile
, aLine
);
138 * Implementation of the nsDebug methods. Note that this code is
139 * always compiled in, in case some other module that uses it is
140 * compiled with debugging even if this library is not.
142 static PRLogModuleInfo
* gDebugLog
;
144 static void InitLog(void)
146 if (0 == gDebugLog
) {
147 gDebugLog
= PR_NewLogModule("nsDebug");
148 gDebugLog
->level
= PR_LOG_DEBUG
;
152 enum nsAssertBehavior
{
153 NS_ASSERT_UNINITIALIZED
,
159 NS_ASSERT_STACK_AND_ABORT
162 static nsAssertBehavior
GetAssertBehavior()
164 static nsAssertBehavior gAssertBehavior
= NS_ASSERT_UNINITIALIZED
;
165 if (gAssertBehavior
!= NS_ASSERT_UNINITIALIZED
)
166 return gAssertBehavior
;
168 #if defined(XP_WIN) || defined(XP_OS2)
169 gAssertBehavior
= NS_ASSERT_TRAP
;
171 gAssertBehavior
= NS_ASSERT_WARN
;
174 const char *assertString
= PR_GetEnv("XPCOM_DEBUG_BREAK");
175 if (!assertString
|| !*assertString
)
176 return gAssertBehavior
;
178 if (!strcmp(assertString
, "warn"))
179 return gAssertBehavior
= NS_ASSERT_WARN
;
181 if (!strcmp(assertString
, "suspend"))
182 return gAssertBehavior
= NS_ASSERT_SUSPEND
;
184 if (!strcmp(assertString
, "stack"))
185 return gAssertBehavior
= NS_ASSERT_STACK
;
187 if (!strcmp(assertString
, "abort"))
188 return gAssertBehavior
= NS_ASSERT_ABORT
;
190 if (!strcmp(assertString
, "trap") || !strcmp(assertString
, "break"))
191 return gAssertBehavior
= NS_ASSERT_TRAP
;
193 if (!strcmp(assertString
, "stack-and-abort"))
194 return gAssertBehavior
= NS_ASSERT_STACK_AND_ABORT
;
196 fprintf(stderr
, "Unrecognized value of XPCOM_DEBUG_BREAK\n");
197 return gAssertBehavior
;
202 FixedBuffer() : curlen(0) { buffer
[0] = '\0'; }
209 StuffFixedBuffer(void *closure
, const char *buf
, PRUint32 len
)
214 FixedBuffer
*fb
= (FixedBuffer
*) closure
;
216 // strip the trailing null, we add it again later
217 if (buf
[len
- 1] == '\0')
220 if (fb
->curlen
+ len
>= sizeof(fb
->buffer
))
221 len
= sizeof(fb
->buffer
) - fb
->curlen
- 1;
224 memcpy(fb
->buffer
+ fb
->curlen
, buf
, len
);
226 fb
->buffer
[fb
->curlen
] = '\0';
232 EXPORT_XPCOM_API(void)
233 NS_DebugBreak(PRUint32 aSeverity
, const char *aStr
, const char *aExpr
,
234 const char *aFile
, PRInt32 aLine
)
239 PRLogModuleLevel ll
= PR_LOG_WARNING
;
240 const char *sevString
= "WARNING";
243 case NS_DEBUG_ASSERTION
:
244 sevString
= "###!!! ASSERTION";
249 sevString
= "###!!! BREAK";
254 sevString
= "###!!! ABORT";
259 aSeverity
= NS_DEBUG_WARNING
;
262 PR_sxprintf(StuffFixedBuffer
, &buf
, "%s: ", sevString
);
265 PR_sxprintf(StuffFixedBuffer
, &buf
, "%s: ", aStr
);
268 PR_sxprintf(StuffFixedBuffer
, &buf
, "'%s', ", aExpr
);
271 PR_sxprintf(StuffFixedBuffer
, &buf
, "file %s, ", aFile
);
274 PR_sxprintf(StuffFixedBuffer
, &buf
, "line %d", aLine
);
276 // Write out the message to the debug log
277 PR_LOG(gDebugLog
, ll
, ("%s", buf
.buffer
));
280 // errors on platforms without a debugdlg ring a bell on stderr
281 #if !defined(XP_WIN) && !defined(XP_OS2)
282 if (ll
!= PR_LOG_WARNING
)
283 fprintf(stderr
, "\07");
286 // Write the message to stderr
287 fprintf(stderr
, "%s\n", buf
.buffer
);
291 case NS_DEBUG_WARNING
:
299 nsTraceRefcntImpl::WalkTheStack(stderr
);
304 // Now we deal with assertions
306 switch (GetAssertBehavior()) {
310 case NS_ASSERT_SUSPEND
:
312 fprintf(stderr
, "Suspending process; attach with the debugger.\n");
319 case NS_ASSERT_STACK
:
320 nsTraceRefcntImpl::WalkTheStack(stderr
);
323 case NS_ASSERT_STACK_AND_ABORT
:
324 nsTraceRefcntImpl::WalkTheStack(stderr
);
325 // Fall through to abort
327 case NS_ASSERT_ABORT
:
337 Abort(const char *aMsg
)
342 //This should exit us
345 //If we are ignored exit this way..
347 #elif defined(XP_UNIX)
349 #elif defined(XP_BEOS)
356 // Don't know how to abort on this platform! call Break() instead
361 // Abort() calls this function, don't call it!
363 Break(const char *aMsg
)
366 #ifndef WINCE // we really just want to crash for now
367 static int ignoreDebugger
;
368 if (!ignoreDebugger
) {
369 const char *shouldIgnoreDebugger
= getenv("XPCOM_DEBUG_DLG");
370 ignoreDebugger
= 1 + (shouldIgnoreDebugger
&& !strcmp(shouldIgnoreDebugger
, "1"));
372 if ((ignoreDebugger
== 2) || !::IsDebuggerPresent()) {
373 DWORD code
= IDRETRY
;
375 /* Create the debug dialog out of process to avoid the crashes caused by
376 * Windows events leaking into our event loop from an in process dialog.
377 * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg).
378 * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792
380 PROCESS_INFORMATION pi
;
382 PRUnichar executable
[MAX_PATH
];
385 memset(&pi
, 0, sizeof(pi
));
387 memset(&si
, 0, sizeof(si
));
389 si
.wShowWindow
= SW_SHOW
;
391 // 2nd arg of CreateProcess is in/out
392 PRUnichar
*msgCopy
= (PRUnichar
*) _alloca((strlen(aMsg
) + 1)*sizeof(PRUnichar
));
393 wcscpy(msgCopy
, (PRUnichar
*)NS_ConvertUTF8toUTF16(aMsg
).get());
395 if(GetModuleFileNameW(GetModuleHandleW(L
"xpcom.dll"), (LPWCH
)executable
, MAX_PATH
) &&
396 NULL
!= (pName
= wcsrchr(executable
, '\\')) &&
399 pName
+1, L
"windbgdlg.exe") &&
400 CreateProcessW((LPCWSTR
)executable
, (LPWSTR
)msgCopy
, NULL
, NULL
, PR_FALSE
,
401 DETACHED_PROCESS
| NORMAL_PRIORITY_CLASS
,
402 NULL
, NULL
, &si
, &pi
)) {
403 WaitForSingleObject(pi
.hProcess
, INFINITE
);
404 GetExitCodeProcess(pi
.hProcess
, &code
);
405 CloseHandle(pi
.hProcess
);
406 CloseHandle(pi
.hThread
);
411 //This should exit us
413 //If we are ignored exit this way..
424 #elif defined(XP_OS2)
426 PR_snprintf(msg
, sizeof(msg
),
427 "%s\n\nClick Cancel to Debug Application.\n"
428 "Click Enter to continue running the Application.", aMsg
);
429 ULONG code
= MBID_ERROR
;
430 code
= WinMessageBox(HWND_DESKTOP
, HWND_DESKTOP
, msg
,
431 "NSGlue_Assertion", 0,
432 MB_ERROR
| MB_ENTERCANCEL
);
434 /* It is possible that we are executing on a thread that doesn't have a
435 * message queue. In that case, the message won't appear, and code will
436 * be 0xFFFF. We'll give the user a chance to debug it by calling
438 * Actually, that's a really bad idea since this happens a lot with threadsafe
439 * assertions and since it means that you can't actually run the debug build
440 * outside a debugger without it crashing constantly.
442 if (( code
== MBID_ENTER
) || (code
== MBID_ERROR
))
446 #elif defined(XP_BEOS)
448 #elif defined(XP_MACOSX)
449 /* Note that we put this Mac OS X test above the GNUC/x86 test because the
450 * GNUC/x86 test is also true on Intel Mac OS X and we want the PPC/x86
451 * impls to be the same.
454 #elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
457 // don't know how to break on this platform
461 static const nsDebugImpl kImpl
;
464 nsDebugImpl::Create(nsISupports
* outer
, const nsIID
& aIID
, void* *aInstancePtr
)
466 NS_ENSURE_NO_AGGREGATION(outer
);
468 return const_cast<nsDebugImpl
*>(&kImpl
)->
469 QueryInterface(aIID
, aInstancePtr
);
472 ////////////////////////////////////////////////////////////////////////////////
475 NS_ErrorAccordingToNSPR()
477 PRErrorCode err
= PR_GetError();
479 case PR_OUT_OF_MEMORY_ERROR
: return NS_ERROR_OUT_OF_MEMORY
;
480 case PR_WOULD_BLOCK_ERROR
: return NS_BASE_STREAM_WOULD_BLOCK
;
481 case PR_FILE_NOT_FOUND_ERROR
: return NS_ERROR_FILE_NOT_FOUND
;
482 case PR_READ_ONLY_FILESYSTEM_ERROR
: return NS_ERROR_FILE_READ_ONLY
;
483 case PR_NOT_DIRECTORY_ERROR
: return NS_ERROR_FILE_NOT_DIRECTORY
;
484 case PR_IS_DIRECTORY_ERROR
: return NS_ERROR_FILE_IS_DIRECTORY
;
485 case PR_LOOP_ERROR
: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK
;
486 case PR_FILE_EXISTS_ERROR
: return NS_ERROR_FILE_ALREADY_EXISTS
;
487 case PR_FILE_IS_LOCKED_ERROR
: return NS_ERROR_FILE_IS_LOCKED
;
488 case PR_FILE_TOO_BIG_ERROR
: return NS_ERROR_FILE_TOO_BIG
;
489 case PR_NO_DEVICE_SPACE_ERROR
: return NS_ERROR_FILE_NO_DEVICE_SPACE
;
490 case PR_NAME_TOO_LONG_ERROR
: return NS_ERROR_FILE_NAME_TOO_LONG
;
491 case PR_DIRECTORY_NOT_EMPTY_ERROR
: return NS_ERROR_FILE_DIR_NOT_EMPTY
;
492 case PR_NO_ACCESS_RIGHTS_ERROR
: return NS_ERROR_FILE_ACCESS_DENIED
;
493 default: return NS_ERROR_FAILURE
;
497 ////////////////////////////////////////////////////////////////////////////////