304

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

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
robottobor
  • 11,595
  • 11
  • 39
  • 37

7 Answers7

563

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.

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
smokris
  • 11,740
  • 2
  • 39
  • 59
  • 15
    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. – Peter Hosey Feb 25 '10 at 13:32
  • 6
    Only on iOS 4.0 and above. – Danra Mar 28 '11 at 08:42
  • Thanks! Is there a way to make this only print the stack trace, say, 6 levels down instead of all the way? – sudo Jul 29 '14 at 16:33
  • 9000, use `backtrace/backtrace_symbols` directly – dymv Feb 27 '15 at 15:10
  • 2
    @sudo It's an array so just define range `[NSThread.callStackSymbols subarrayWithRange:NSMakeRange(0, MIN(6, NSThread.callStackSymbols.count))];` – Albert Renshaw Mar 22 '22 at 04:46
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;
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Zayin Krige
  • 3,229
  • 1
  • 35
  • 34
  • 4
    Gah... Apple should make this a standard at least while developing an application. A bunch of memory addresses is... archaic – Russ Sep 11 '13 at 20:02
  • I put your improvements in my answer; I did this before ARC. Thanks. – n13 Apr 11 '14 at 08:18
  • 1
    This *doesn't* work in all situations. This is a better approach if you want to catch all uncaught exceptions: http://codereview.stackexchange.com/questions/56162/unhandled-exception-handler-that-captures-a-screenshot (The code in that question is a little overcomplicated, but it also does more than simply log the call stack symbols.) – nhgrif Jul 12 '14 at 21:57
  • You can add `NSLog(@"[Error] - %@ %@", exception.name, exception.reason);` if you want the actual exception too – Corentin S. Mar 25 '15 at 15:02
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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
vt.
  • 1,073
  • 8
  • 12
  • 6
    Apparently available in iOS 4 but not 3.2. Here's what I used, shamelessly copied from the backtrace man page: #include ... 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); – mharper Aug 28 '10 at 22:10
  • 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. – Tertium Sep 28 '12 at 19:38
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]
Cœur
  • 37,241
  • 25
  • 195
  • 267
Max Stewart
  • 3,573
  • 26
  • 28
  • 1
    Note, though that this will only work within a registered exception handler (not, e.g., in a @catch block) – Barry Wark Oct 23 '08 at 00:13
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.

Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
1

In swift print this way:

print("stack trace:\(Thread.callStackSymbols)")
Dipak
  • 2,263
  • 1
  • 21
  • 27
-2

If you want to get it as NSString.

[NSThread  callStackSymbols].description
miragessee
  • 313
  • 1
  • 4
  • 14