VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp@ 58038

Last change on this file since 58038 was 3372, checked in by vboxsync, 17 years ago

XPCOM: Executable and DLL names may be specified from makefiles, for consistency.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette