1 /* -*- Mode: C++; tab-width: 2; 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
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with 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 * Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2008
20 * the Initial Developer. All Rights Reserved.
23 * Josh Aas <josh@mozilla.com>
24 * Robert O'Callahan <robert@ocallahan.org>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * 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 NPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef nsObjCExceptions_h_
41 #define nsObjCExceptions_h_
43 #import <Foundation/Foundation.h>
46 #import <ExceptionHandling/NSExceptionHandler.h>
49 #if defined(MOZ_CRASHREPORTER) && defined(__cplusplus)
50 #include "nsICrashReporter.h"
52 #include "nsServiceManagerUtils.h"
59 // See Mozilla bug 163260.
60 // This file can only be included in an Objective-C context.
62 static void nsObjCExceptionLog(NSException
* aException
)
64 NSLog(@
"Mozilla has caught an Obj-C exception [%@: %@]",
65 [aException name
], [aException reason
]);
67 #if defined(MOZ_CRASHREPORTER) && defined(__cplusplus)
68 // Attach exception info to the crash report.
69 nsCOMPtr
<nsICrashReporter
> crashReporter
=
70 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
72 crashReporter
->AppendObjCExceptionInfoToAppNotes(static_cast<void*>(aException
));
77 // Try to get stack information out of the exception. 10.5 returns the stack
78 // info with the callStackReturnAddresses selector.
79 NSArray
*stackTrace
= nil
;
80 if ([aException respondsToSelector
:@
selector(callStackReturnAddresses
)]) {
81 NSArray
* addresses
= (NSArray
*)
82 [aException performSelector
:@
selector(callStackReturnAddresses
)];
83 if ([addresses count
])
84 stackTrace
= addresses
;
87 // 10.4 doesn't respond to callStackReturnAddresses so we'll try to pull the
88 // stack info out of the userInfo. It might not be there, sadly :(
90 stackTrace
= [[aException userInfo
] objectForKey
:NSStackTraceKey
];
93 // The command line should look like this:
94 // /usr/bin/atos -p <pid> -printHeader <stack frame addresses>
95 NSMutableArray
*args
=
96 [NSMutableArray arrayWithCapacity
:[stackTrace count
] + 3];
98 [args addObject
:@
"-p"];
99 int pid
= [[NSProcessInfo processInfo
] processIdentifier
];
100 [args addObject
:[NSString stringWithFormat
:@
"%d", pid
]];
102 [args addObject
:@
"-printHeader"];
104 unsigned int stackCount
= [stackTrace count
];
105 unsigned int stackIndex
= 0;
106 for (; stackIndex
< stackCount
; stackIndex
++)
107 [args addObject
:[[stackTrace objectAtIndex
:stackIndex
] stringValue
]];
109 NSPipe
*outPipe
= [NSPipe pipe
];
111 NSTask
*task
= [[NSTask alloc
] init
];
112 [task setLaunchPath
:@
"/usr/bin/atos"];
113 [task setArguments
:args
];
114 [task setStandardOutput
:outPipe
];
115 [task setStandardError
:outPipe
];
117 NSLog(@
"Generating stack trace for Obj-C exception...");
119 // This will throw an exception if the atos tool cannot be found, and in
120 // that case we'll just hit our @catch block below.
123 [task waitUntilExit
];
127 [[outPipe fileHandleForReading
] readDataToEndOfFile
];
128 NSString
*outString
=
129 [[NSString alloc
] initWithData
:outData encoding
:NSUTF8StringEncoding
];
131 NSLog(@
"Stack trace:\n%@", outString
);
136 NSLog(@
"<No stack information available for Obj-C exception>");
139 @
catch (NSException
*exn
) {
140 NSLog(@
"Failed to generate stack trace for Obj-C exception [%@: %@]",
141 [exn name
], [exn reason
]);
146 static void nsObjCExceptionAbort()
148 // We need to raise a mach-o signal here, the Mozilla crash reporter on
149 // Mac OS X does not respond to POSIX signals. Raising mach-o signals directly
150 // is tricky so we do it by just derefing a null pointer.
155 static void nsObjCExceptionLogAbort(NSException
*e
)
157 nsObjCExceptionLog(e
);
158 nsObjCExceptionAbort();
161 #define NS_OBJC_TRY(_e, _fail) \
163 @catch(NSException *_exn) { \
164 nsObjCExceptionLog(_exn); \
168 #define NS_OBJC_TRY_EXPR(_e, _fail) \
171 @try { _tmp = (_e); } \
172 @catch(NSException *_exn) { \
173 nsObjCExceptionLog(_exn); \
179 #define NS_OBJC_TRY_EXPR_NULL(_e) \
180 NS_OBJC_TRY_EXPR(_e, 0)
182 #define NS_OBJC_TRY_IGNORE(_e) \
185 // To reduce code size the abort versions do not reuse above macros. This allows
186 // catch blocks to only contain one call.
188 #define NS_OBJC_TRY_ABORT(_e) \
190 @catch(NSException *_exn) { \
191 nsObjCExceptionLogAbort(_exn); \
194 #define NS_OBJC_TRY_EXPR_ABORT(_e) \
197 @try { _tmp = (_e); } \
198 @catch(NSException *_exn) { \
199 nsObjCExceptionLogAbort(_exn); \
204 // For wrapping blocks of Obj-C calls. Terminates app after logging.
205 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK @try {
206 #define NS_OBJC_END_TRY_ABORT_BLOCK } @catch(NSException *_exn) { \
207 nsObjCExceptionLogAbort(_exn); \
210 // Same as above ABORT_BLOCK but returns a value after the try/catch block to
211 // suppress compiler warnings. This allows us to avoid having to refactor code
212 // to get scoping right when wrapping an entire method.
214 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL @try {
215 #define NS_OBJC_END_TRY_ABORT_BLOCK_NIL } @catch(NSException *_exn) { \
216 nsObjCExceptionLogAbort(_exn); \
220 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL @try {
221 #define NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL } @catch(NSException *_exn) { \
222 nsObjCExceptionLogAbort(_exn); \
226 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT @try {
227 #define NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT } @catch(NSException *_exn) { \
228 nsObjCExceptionLogAbort(_exn);\
230 return NS_ERROR_FAILURE;
232 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN @try {
233 #define NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(_rv) } @catch(NSException *_exn) { \
234 nsObjCExceptionLogAbort(_exn);\
238 #define NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK @try {
239 #define NS_OBJC_END_TRY_LOGONLY_BLOCK } @catch(NSException *_exn) { \
240 nsObjCExceptionLog(_exn); \
243 #endif // nsObjCExceptions_h_