Jak wydrukować ślad stosu na konsoli / zalogować się w Cocoa?

293

Chciałbym rejestrować ślad połączenia podczas niektórych punktów, takich jak nieudane stwierdzenia lub nieprzechwycone wyjątki.

robottobor
źródło

Odpowiedzi:

544
 NSLog(@"%@",[NSThread callStackSymbols]);

Ten kod działa na dowolnym wątku.

smokris
źródło
14
Nowość w systemie Mac OS X 10.6, który nie istniał, gdy pierwotnie zadano to pytanie. W przypadku wersji Snow Leopard użyj funkcji backtracei backtrace_symbols; patrz strona podręcznika śledzenia (3).
Peter Hosey,
6
Tylko w iOS 4.0 i nowszych.
Danra
Dzięki! Czy istnieje sposób, aby wydrukować tylko ślad stosu, powiedzmy, 6 poziomów w dół zamiast do końca?
sudo
9000, użyj backtrace/backtrace_symbolsbezpośrednio
dymv
34

Odpowiedź n13 nie do końca działała - zmodyfikowałem ją nieco, aby to wymyślić

#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;
    }
}
Zayin Krige
źródło
4
Gah ... Apple powinien uczynić to standardem przynajmniej podczas tworzenia aplikacji. Kilka adresów pamięci jest ... archaicznych
Russ
W poprawce podaję twoje ulepszenia; Zrobiłem to przed ARC. Dzięki.
n13
1
To nie działa we wszystkich sytuacjach. Jest to lepsze podejście, jeśli chcesz wychwycić wszystkie nieprzechwycone wyjątki: codereview.stackexchange.com/questions/56162/... (Kod w tym pytaniu jest nieco skomplikowany, ale nie tylko rejestruje symbole stosu wywołań).
nhgrif,
Możesz dodać, NSLog(@"[Error] - %@ %@", exception.name, exception.reason);jeśli chcesz również faktyczny wyjątek
Corentin S.
9

Kakao już rejestruje ślad stosu w przypadku niewyłapanych wyjątków od konsoli, chociaż są to tylko surowe adresy pamięci. Jeśli potrzebujesz informacji symbolicznych w konsoli, jest jakiś przykładowy kod od Apple.

Jeśli chcesz wygenerować ślad stosu w dowolnym punkcie swojego kodu (i jesteś w systemie Leopard), zobacz stronę podręcznika śledzenia. Przed Leopardem musiałeś przekopać sam stos wywołań.

vt.
źródło
6
Podobno dostępny w iOS 4, ale nie 3.2. Oto, czego użyłem, bezwstydnie skopiowałem ze strony podręcznika śledzenia: #include <execinfo.h> ... void * callstack [128]; int i, frames = backtrace (callstack, 128); char ** strs = backtrace_symbols (callstack, frames); for (i = 0; i <klatki; ++ i) {printf ("% s \ n", strs [i]); } free (strs);
mharper
Wywoływany w HandleException zapisuje ślad samej funkcji modułu obsługi, podczas gdy [NSException callStackSymbols] pokazuje stos miejsca, w którym wystąpił wyjątek. Ale jeśli zastąpisz „backtrace (...)”: „NSArray arr = [ex callStackReturnAddresses]; int frames = arr.count; for (i = 0; i <frames; ++ i) callstack [i] = ( void) [((NSNumber *) [arr objectAtIndex: i]) intValue]; " otrzymasz bieżący ślad stosu wyjątku. Tak działa [NSException callStackSymbols], przypuszczam: ślady, które zwracają, są równe i w obu wywołaniach aplikacji są zastępowane przez _mh_execute_header w wersji.
Tertium
6

To prawie mówi ci, co masz robić.

Zasadniczo musisz skonfigurować obsługę wyjątków aplikacji do rejestrowania, na przykład:

#import <ExceptionHandling/NSExceptionHandler.h>

[[NSExceptionHandler defaultExceptionHandler] 
                  setExceptionHandlingMask: NSLogUncaughtExceptionMask | 
                                            NSLogUncaughtSystemExceptionMask | 
                                            NSLogUncaughtRuntimeErrorMask]
Max Stewart
źródło
1
Należy jednak pamiętać, że będzie to działać tylko w ramach zarejestrowanego modułu obsługi wyjątków (nie np. W bloku @catch)
Barry Wark
1

W szybki druk w ten sposób:

print("stack trace:\(Thread.callStackSymbols)")
Deepak
źródło