VirtualBox

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

Last change on this file since 549 was 1, checked in by vboxsync, 55 years ago

import

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