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
:
326 nsTraceRefcntImpl::WalkTheStack(stderr
);
331 // Now we deal with assertions
333 switch (GetAssertBehavior()) {
337 case NS_ASSERT_SUSPEND
:
339 fprintf(stderr
, "Suspending process; attach with the debugger.\n");
346 case NS_ASSERT_STACK
:
347 nsTraceRefcntImpl::WalkTheStack(stderr
);
350 case NS_ASSERT_STACK_AND_ABORT
:
351 nsTraceRefcntImpl::WalkTheStack(stderr
);
352 // Fall through to abort
354 case NS_ASSERT_ABORT
:
364 Abort(const char *aMsg
)
367 //This should exit us
369 //If we are ignored exit this way..
371 #elif defined(XP_UNIX)
373 #elif defined(XP_BEOS)
380 // Don't know how to abort on this platform! call Break() instead
385 // Abort() calls this function, don't call it!
387 Break(const char *aMsg
)
390 #ifndef WINCE // we really just want to crash for now
391 static int ignoreDebugger
;
392 if (!ignoreDebugger
) {
393 const char *shouldIgnoreDebugger
= getenv("XPCOM_DEBUG_DLG");
394 ignoreDebugger
= 1 + (shouldIgnoreDebugger
&& !strcmp(shouldIgnoreDebugger
, "1"));
396 if((ignoreDebugger
== 2) || !InDebugger()) {
397 DWORD code
= IDRETRY
;
399 /* Create the debug dialog out of process to avoid the crashes caused by
400 * Windows events leaking into our event loop from an in process dialog.
401 * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg).
402 * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792
404 PROCESS_INFORMATION pi
;
406 char executable
[MAX_PATH
];
409 memset(&pi
, 0, sizeof(pi
));
411 memset(&si
, 0, sizeof(si
));
413 si
.wShowWindow
= SW_SHOW
;
415 // 2nd arg of CreateProcess is in/out
416 char *msgCopy
= (char*) _alloca(strlen(aMsg
) + 1);
417 strcpy(msgCopy
, aMsg
);
419 if(GetModuleFileName(GetModuleHandle("xpcom.dll"), executable
, MAX_PATH
) &&
420 NULL
!= (pName
= strrchr(executable
, '\\')) &&
421 NULL
!= strcpy(pName
+1, "windbgdlg.exe") &&
422 CreateProcess(executable
, msgCopy
, NULL
, NULL
, PR_FALSE
,
423 DETACHED_PROCESS
| NORMAL_PRIORITY_CLASS
,
424 NULL
, NULL
, &si
, &pi
)) {
425 WaitForSingleObject(pi
.hProcess
, INFINITE
);
426 GetExitCodeProcess(pi
.hProcess
, &code
);
427 CloseHandle(pi
.hProcess
);
428 CloseHandle(pi
.hThread
);
433 //This should exit us
435 //If we are ignored exit this way..
446 #elif defined(XP_OS2)
448 PR_snprintf(msg
, sizeof(msg
),
449 "%s\n\nClick Cancel to Debug Application.\n"
450 "Click Enter to continue running the Application.", aMsg
);
451 ULONG code
= MBID_ERROR
;
452 code
= WinMessageBox(HWND_DESKTOP
, HWND_DESKTOP
, msg
,
453 "NSGlue_Assertion", 0,
454 MB_ERROR
| MB_ENTERCANCEL
);
456 /* It is possible that we are executing on a thread that doesn't have a
457 * message queue. In that case, the message won't appear, and code will
458 * be 0xFFFF. We'll give the user a chance to debug it by calling
460 * Actually, that's a really bad idea since this happens a lot with threadsafe
461 * assertions and since it means that you can't actually run the debug build
462 * outside a debugger without it crashing constantly.
464 if (( code
== MBID_ENTER
) || (code
== MBID_ERROR
))
468 #elif defined(XP_BEOS)
470 #elif defined(XP_MACOSX)
471 /* Note that we put this Mac OS X test above the GNUC/x86 test because the
472 * GNUC/x86 test is also true on Intel Mac OS X and we want the PPC/x86
473 * impls to be the same.
476 #elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
479 // don't know how to break on this platform
483 static const nsDebugImpl kImpl
;
486 nsDebugImpl::Create(nsISupports
* outer
, const nsIID
& aIID
, void* *aInstancePtr
)
488 NS_ENSURE_NO_AGGREGATION(outer
);
490 return const_cast<nsDebugImpl
*>(&kImpl
)->
491 QueryInterface(aIID
, aInstancePtr
);
494 ////////////////////////////////////////////////////////////////////////////////
497 NS_ErrorAccordingToNSPR()
499 PRErrorCode err
= PR_GetError();
501 case PR_OUT_OF_MEMORY_ERROR
: return NS_ERROR_OUT_OF_MEMORY
;
502 case PR_WOULD_BLOCK_ERROR
: return NS_BASE_STREAM_WOULD_BLOCK
;
503 case PR_FILE_NOT_FOUND_ERROR
: return NS_ERROR_FILE_NOT_FOUND
;
504 case PR_READ_ONLY_FILESYSTEM_ERROR
: return NS_ERROR_FILE_READ_ONLY
;
505 case PR_NOT_DIRECTORY_ERROR
: return NS_ERROR_FILE_NOT_DIRECTORY
;
506 case PR_IS_DIRECTORY_ERROR
: return NS_ERROR_FILE_IS_DIRECTORY
;
507 case PR_LOOP_ERROR
: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK
;
508 case PR_FILE_EXISTS_ERROR
: return NS_ERROR_FILE_ALREADY_EXISTS
;
509 case PR_FILE_IS_LOCKED_ERROR
: return NS_ERROR_FILE_IS_LOCKED
;
510 case PR_FILE_TOO_BIG_ERROR
: return NS_ERROR_FILE_TOO_BIG
;
511 case PR_NO_DEVICE_SPACE_ERROR
: return NS_ERROR_FILE_NO_DEVICE_SPACE
;
512 case PR_NAME_TOO_LONG_ERROR
: return NS_ERROR_FILE_NAME_TOO_LONG
;
513 case PR_DIRECTORY_NOT_EMPTY_ERROR
: return NS_ERROR_FILE_DIR_NOT_EMPTY
;
514 case PR_NO_ACCESS_RIGHTS_ERROR
: return NS_ERROR_FILE_ACCESS_DENIED
;
515 default: return NS_ERROR_FAILURE
;
519 ////////////////////////////////////////////////////////////////////////////////