1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // Undo the damage that exception_defines.h does.
10 #ifndef nsObjCExceptions_h_
11 #define nsObjCExceptions_h_
13 #import <Foundation/Foundation.h>
16 #import <ExceptionHandling/NSExceptionHandler.h>
19 #if defined(MOZ_CRASHREPORTER) && defined(__cplusplus)
20 #include "nsICrashReporter.h"
22 #include "nsServiceManagerUtils.h"
29 // Undo the damage that exception_defines.h does.
33 /* NOTE: Macros that claim to abort no longer abort, see bug 486574.
34 * If you actually want to log and abort, call "nsObjCExceptionLogAbort"
35 * from an exception handler. At some point we will fix this by replacing
36 * all macros in the tree with appropriately-named macros.
39 // See Mozilla bug 163260.
40 // This file can only be included in an Objective-C context.
42 __attribute__((unused
))
43 static void nsObjCExceptionLog(NSException
* aException
)
45 NSLog(@
"Mozilla has caught an Obj-C exception [%@: %@]",
46 [aException name
], [aException reason
]);
48 #if defined(MOZ_CRASHREPORTER) && defined(__cplusplus)
49 // Attach exception info to the crash report.
50 nsCOMPtr
<nsICrashReporter
> crashReporter
=
51 do_GetService("@mozilla.org/toolkit/crash-reporter;1");
53 crashReporter
->AppendObjCExceptionInfoToAppNotes(static_cast<void*>(aException
));
58 // Try to get stack information out of the exception. 10.5 returns the stack
59 // info with the callStackReturnAddresses selector.
60 NSArray
*stackTrace
= nil
;
61 if ([aException respondsToSelector
:@
selector(callStackReturnAddresses
)]) {
62 NSArray
* addresses
= (NSArray
*)
63 [aException performSelector
:@
selector(callStackReturnAddresses
)];
64 if ([addresses count
])
65 stackTrace
= addresses
;
68 // 10.4 doesn't respond to callStackReturnAddresses so we'll try to pull the
69 // stack info out of the userInfo. It might not be there, sadly :(
71 stackTrace
= [[aException userInfo
] objectForKey
:NSStackTraceKey
];
74 // The command line should look like this:
75 // /usr/bin/atos -p <pid> -printHeader <stack frame addresses>
76 NSMutableArray
*args
=
77 [NSMutableArray arrayWithCapacity
:[stackTrace count
] + 3];
79 [args addObject
:@
"-p"];
80 int pid
= [[NSProcessInfo processInfo
] processIdentifier
];
81 [args addObject
:[NSString stringWithFormat
:@
"%d", pid
]];
83 [args addObject
:@
"-printHeader"];
85 unsigned int stackCount
= [stackTrace count
];
86 unsigned int stackIndex
= 0;
87 for (; stackIndex
< stackCount
; stackIndex
++) {
88 unsigned long address
=
89 [[stackTrace objectAtIndex
:stackIndex
] unsignedLongValue
];
90 [args addObject
:[NSString stringWithFormat
:@
"0x%lx", address
]];
93 NSPipe
*outPipe
= [NSPipe pipe
];
95 NSTask
*task
= [[NSTask alloc
] init
];
96 [task setLaunchPath
:@
"/usr/bin/atos"];
97 [task setArguments
:args
];
98 [task setStandardOutput
:outPipe
];
99 [task setStandardError
:outPipe
];
101 NSLog(@
"Generating stack trace for Obj-C exception...");
103 // This will throw an exception if the atos tool cannot be found, and in
104 // that case we'll just hit our @catch block below.
107 [task waitUntilExit
];
111 [[outPipe fileHandleForReading
] readDataToEndOfFile
];
112 NSString
*outString
=
113 [[NSString alloc
] initWithData
:outData encoding
:NSUTF8StringEncoding
];
115 NSLog(@
"Stack trace:\n%@", outString
);
120 NSLog(@
"<No stack information available for Obj-C exception>");
123 @
catch (NSException
*exn
) {
124 NSLog(@
"Failed to generate stack trace for Obj-C exception [%@: %@]",
125 [exn name
], [exn reason
]);
130 __attribute__((unused
))
131 static void nsObjCExceptionAbort()
133 // We need to raise a mach-o signal here, the Mozilla crash reporter on
134 // Mac OS X does not respond to POSIX signals. Raising mach-o signals directly
135 // is tricky so we do it by just derefing a null pointer.
140 __attribute__((unused
))
141 static void nsObjCExceptionLogAbort(NSException
*e
)
143 nsObjCExceptionLog(e
);
144 nsObjCExceptionAbort();
147 #define NS_OBJC_TRY(_e, _fail) \
149 @catch(NSException *_exn) { \
150 nsObjCExceptionLog(_exn); \
154 #define NS_OBJC_TRY_EXPR(_e, _fail) \
157 @try { _tmp = (_e); } \
158 @catch(NSException *_exn) { \
159 nsObjCExceptionLog(_exn); \
165 #define NS_OBJC_TRY_EXPR_NULL(_e) \
166 NS_OBJC_TRY_EXPR(_e, 0)
168 #define NS_OBJC_TRY_IGNORE(_e) \
171 // To reduce code size the abort versions do not reuse above macros. This allows
172 // catch blocks to only contain one call.
174 #define NS_OBJC_TRY_ABORT(_e) \
176 @catch(NSException *_exn) { \
177 nsObjCExceptionLog(_exn); \
180 #define NS_OBJC_TRY_EXPR_ABORT(_e) \
183 @try { _tmp = (_e); } \
184 @catch(NSException *_exn) { \
185 nsObjCExceptionLog(_exn); \
190 // For wrapping blocks of Obj-C calls. Does not actually terminate.
191 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK @try {
192 #define NS_OBJC_END_TRY_ABORT_BLOCK } @catch(NSException *_exn) { \
193 nsObjCExceptionLog(_exn); \
196 // Same as above ABORT_BLOCK but returns a value after the try/catch block to
197 // suppress compiler warnings. This allows us to avoid having to refactor code
198 // to get scoping right when wrapping an entire method.
200 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL @try {
201 #define NS_OBJC_END_TRY_ABORT_BLOCK_NIL } @catch(NSException *_exn) { \
202 nsObjCExceptionLog(_exn); \
206 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL @try {
207 #define NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL } @catch(NSException *_exn) { \
208 nsObjCExceptionLog(_exn); \
212 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT @try {
213 #define NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT } @catch(NSException *_exn) { \
214 nsObjCExceptionLog(_exn); \
216 return NS_ERROR_FAILURE;
218 #define NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN @try {
219 #define NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(_rv) } @catch(NSException *_exn) { \
220 nsObjCExceptionLog(_exn);\
224 #define NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK @try {
225 #define NS_OBJC_END_TRY_LOGONLY_BLOCK } @catch(NSException *_exn) { \
226 nsObjCExceptionLog(_exn); \
229 #define NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK_RETURN @try {
230 #define NS_OBJC_END_TRY_LOGONLY_BLOCK_RETURN(_rv) } @catch(NSException *_exn) { \
231 nsObjCExceptionLog(_exn); \
235 #endif // nsObjCExceptions_h_