How do you print out a stack trace to the console/log in Cocoa?
Asked Answered
P

7

305

I'd like to log the call trace during certain points, like failed assertions, or uncaught exceptions.

Pants answered 20/10, 2008 at 22:24 Comment(0)
N
564

This code works on any thread:

NSLog(@"%@", NSThread.callStackSymbols);

Returns an array containing the call stack symbols. Each element is an NSString object with a value in a format determined by the backtrace_symbols() function.

Nuclease answered 24/2, 2010 at 0:42 Comment(6)
New in Mac OS X 10.6, which didn't exist when this question was originally asked. For pre-Snow-Leopard, use the backtrace and backtrace_symbols functions; see the backtrace(3) manpage.Batten
Only on iOS 4.0 and above.Bomber
Thanks! Is there a way to make this only print the stack trace, say, 6 levels down instead of all the way?Argentiferous
9000, use backtrace/backtrace_symbols directlyOpaque
@Argentiferous It's an array so just define range [NSThread.callStackSymbols subarrayWithRange:NSMakeRange(0, MIN(6, NSThread.callStackSymbols.count))];Glory
For Swift, see https://mcmap.net/q/99518/-how-do-you-print-out-a-stack-trace-to-the-console-log-in-cocoaAnacreontic
E
35

n13's answer didn't quite work - I modified it slightly to come up with this

#import <UIKit/UIKit.h>

#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int retval;
        @try{
            retval = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        @catch (NSException *exception)
        {
            NSLog(@"Gosh!!! %@", [exception callStackSymbols]);
            @throw;
        }
        return retval;
    }
}
Emmery answered 9/1, 2013 at 5:13 Comment(4)
Gah... Apple should make this a standard at least while developing an application. A bunch of memory addresses is... archaicSciatica
I put your improvements in my answer; I did this before ARC. Thanks.Pyrophoric
This doesn't work in all situations. This is a better approach if you want to catch all uncaught exceptions: codereview.stackexchange.com/questions/56162/… (The code in that question is a little overcomplicated, but it also does more than simply log the call stack symbols.)Jointure
You can add NSLog(@"[Error] - %@ %@", exception.name, exception.reason); if you want the actual exception tooMonique
R
9

Cocoa already logs the stack trace on uncaught exceptions to the console although they're just raw memory addresses. If you want symbolic information in the console there's some sample code from Apple.

If you want to generate a stack trace at an arbitrary point in your code (and you're on Leopard), see the backtrace man page. Before Leopard, you actually had to dig through the call stack itself.

Rexrexana answered 20/10, 2008 at 22:58 Comment(2)
Apparently available in iOS 4 but not 3.2. Here's what I used, shamelessly copied from the backtrace man page: #include <execinfo.h> ... void* callstack[128]; int i, frames = backtrace(callstack, 128); char** strs = backtrace_symbols(callstack, frames); for (i = 0; i < frames; ++i) { printf("%s\n", strs[i]); } free(strs);Duration
Being called in HandleException it writes back trace of handler function itself, while [NSException callStackSymbols] shows stack of the place where exception has raised. But if you replace "backtrace(...)" with: "NSArray arr = [ex callStackReturnAddresses]; int frames = arr.count; for (i = 0; i < frames; ++i) callstack[i] = (void) [((NSNumber *) [arr objectAtIndex:i]) intValue];" you will get current exception stack trace. This is how [NSException callStackSymbols] works, I suppose: traces they return are equal and in both app calls are replaced by _mh_execute_header in release.Bryozoan
M
6

This pretty much tells you what to do.

Essentially you need to set up the applications exception handling to log, something like:

#import <ExceptionHandling/NSExceptionHandler.h>

[[NSExceptionHandler defaultExceptionHandler] 
                  setExceptionHandlingMask: NSLogUncaughtExceptionMask | 
                                            NSLogUncaughtSystemExceptionMask | 
                                            NSLogUncaughtRuntimeErrorMask]
Mode answered 20/10, 2008 at 22:28 Comment(1)
Note, though that this will only work within a registered exception handler (not, e.g., in a @catch block)Newell
S
2

For exceptions, you can use the NSStackTraceKey member of the exception's userInfo dictionary to do this. See Controlling a Program's Response to Exceptions on Apple's website.

Sennacherib answered 20/10, 2008 at 22:44 Comment(1)
How to use in Swift?Kamilah
S
2

In swift print this way:

print("stack trace:\(Thread.callStackSymbols)")
Scottiescottish answered 12/11, 2018 at 13:57 Comment(0)
S
-2

If you want to get it as NSString.

[NSThread  callStackSymbols].description
Sanious answered 9/11, 2021 at 7:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.