Como você imprime um rastreamento de pilha no console / logon Cocoa?


293

Eu gostaria de registrar o rastreamento de chamadas durante determinados pontos, como afirmações com falha ou exceções não capturadas.

Respostas:


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

Este código funciona em qualquer thread.


14
Novo no Mac OS X 10.6, que não existia quando esta pergunta foi feita originalmente. Para pré-Snow-Leopard, use as funções backtracee backtrace_symbols; consulte a página de manual backtrace (3).
Peter Hosey

6
Somente no iOS 4.0 e superior.
Danra 28/03

Obrigado! Existe uma maneira de fazer isso imprimir apenas o rastreamento da pilha, digamos, 6 níveis abaixo, em vez de todo o caminho?
sudo

9000, use backtrace/backtrace_symbolsdiretamente
dymv 27/02

34

A resposta de n13 não funcionou muito bem - eu a modifiquei um pouco para criar essa

#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;
    }
}

4
Gah ... A Apple deve fazer disso um padrão pelo menos durante o desenvolvimento de um aplicativo. Um grupo de endereços de memória é ... arcaica
Russ

Eu coloquei suas melhorias na minha resposta; Eu fiz isso antes do ARC. Obrigado.
n13

1
Isso não funciona em todas as situações. Essa é uma abordagem melhor se você deseja capturar todas as exceções não capturadas: codereview.stackexchange.com/questions/56162/… (O código nessa pergunta é um pouco complicado demais , mas também faz mais do que simplesmente registrar os símbolos da pilha de chamadas).
Nhgrif 12/07

Você pode adicionar NSLog(@"[Error] - %@ %@", exception.name, exception.reason);se quiser que a exceção real também
Corentin S.

9

O cacau já registra o rastreamento de pilha em exceções não capturadas no console, embora sejam apenas endereços de memória bruta. Se você quiser informações simbólicas no console, há algum código de amostra da Apple.

Se você deseja gerar um rastreamento de pilha em um ponto arbitrário no seu código (e você está no Leopard), consulte a página de manual do backtrace. Antes do Leopard, você realmente precisava vasculhar a própria pilha de chamadas.


6
Aparentemente disponível no iOS 4, mas não no 3.2. Aqui está o que eu usei, copiado descaradamente da página de manual do backtrace: #include <execinfo.h> ... void * callstack [128]; int i, frames = backtrace (pilha de chamadas, 128); char ** strs = backtrace_symbols (pilha de chamadas, quadros); para (i = 0; i <quadros; ++ i) {printf ("% s \ n", strs [i]); } livre (strs);
precisa saber é o seguinte

Ao ser chamado no HandleException, ele grava o rastreio da função do manipulador, enquanto [NSException callStackSymbols] mostra a pilha do local onde a exceção foi gerada. Mas se você substituir "backtrace (...)" por: "NSArray arr = [ex callStackReturnAddresses]; int frames = arr.count; for (i = 0; i <frames; ++ i) callstack [i] = ( void) [((NSNumber *) [arr objectAtIndex: i]) intValue]; " você receberá o rastreamento de pilha de exceção atual. É assim que [NSException callStackSymbols] funciona, suponho: os rastreamentos que eles retornam são iguais e nas chamadas de aplicativos são substituídas por _mh_execute_header no lançamento.
Tertium 28/09/12

6

Isso praticamente diz o que você deve fazer.

Essencialmente, você precisa configurar o tratamento de exceções dos aplicativos para registrar, algo como:

#import <ExceptionHandling/NSExceptionHandler.h>

[[NSExceptionHandler defaultExceptionHandler] 
                  setExceptionHandlingMask: NSLogUncaughtExceptionMask | 
                                            NSLogUncaughtSystemExceptionMask | 
                                            NSLogUncaughtRuntimeErrorMask]

1
Note, no entanto, que isto só irá funcionar dentro de um manipulador de exceção registrado (e não, por exemplo, em um bloco @catch)
Barry Wark


1

Em impressão rápida, desta maneira:

print("stack trace:\(Thread.callStackSymbols)")
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.