Il debug di Xcode 4.2 non simboleggia la chiamata in pila


140

Ho un problema con il debug di Xcode 4.2 in un simulatore / dispositivo iOS 5. Il codice seguente si arresta in modo anomalo, come previsto:

NSArray *arr=[NSArray array];
[arr objectAtIndex:100];

In iOS 4, ottengo un'utile traccia stack di numeri esadecimali. Ma in iOS 5, mi dà solo:

*** First throw call stack:
(0x16b4052 0x1845d0a 0x16a0674 0x294c 0x6f89d6 0x6f98a6 0x708743 0x7091f8 0x7fcaa9 0x2257fa9 0x16881c5 0x15ed022 0x15eb90a 0x15eadb4 0x15eaccb 0x6f02a7 0x6faa93 0x2889 0x2805)

Grazie.

Risposte:


256

Nulla di ciò che ho provato avrebbe risolto questo problema (provato entrambi i compilatori, entrambi i debugger, ecc.) Dopo aver aggiornato XCode per l'aggiornamento di iOS 5, nessuna traccia dello stack sembrava funzionare.

Tuttavia, ho trovato una soluzione efficace: creare il mio gestore di eccezioni (che è utile anche per altri motivi). Innanzitutto, crea una funzione che gestirà l'errore e lo invii alla console (così come qualsiasi altra cosa tu voglia fare con esso):

void uncaughtExceptionHandler(NSException *exception) {
    NSLog(@"CRASH: %@", exception);
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    // Internal error reporting
}

Successivamente, aggiungi il gestore eccezioni al delegato dell'app:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    // Normal launch stuff
}

Questo è tutto!

Se questo non funziona, ci sono solo due possibili ragioni :

  1. Qualcosa sta sovrascrivendo la tua NSSetUncaughtExceptionHandlerchiamata (può esserci un solo gestore per l'intera app). Ad esempio, alcune librerie di terze parti impostano il proprio uncaughtExceptionHandler. Quindi, prova a impostarlo alla fine della tua didFinishLaunchingWithOptionsfunzione (o disabilita selettivamente le librerie di terze parti). O meglio ancora, imposta un punto di interruzione simbolico NSSetUncaughtExceptionHandlerper vedere rapidamente chi lo sta chiamando. Quello che potresti voler fare è modificare quello attuale invece di aggiungerne un altro.
  2. In realtà non stai riscontrando un'eccezione (ad esempio, nonEXC_BAD_ACCESS è un'eccezione; merito ai commenti di @Erik B, di seguito)

1
Sono contento di ascoltarlo :) Trovo utile scrivere il registro degli arresti anomali in un file e chiedere all'utente di inviarlo al prossimo avvio (solo in modalità di rilascio, per non ostacolare il debug). Questo mi permette di ottenere ottime segnalazioni di bug ... e gli utenti sanno che il loro problema è stato risolto :)
Zane Claes,

2
Questo non sembra funzionare: la uncaughtExceptionHandlerroutine non viene mai invocata.
Hot Licks

1
Puoi per favore essere più specifico su come usarlo? Non sembra funzionare per me.
Danut Pralea,

1
XCode piuttosto triste non lo mostra per noi.
Authman Apatira,

1
Molto apprezzato! È sconcertante che Apple non implementi questo tipo di funzionalità rudimentale nell'IDE.
devios1

110

C'è un'utile opzione per aggiungere un Breakpoint di eccezione (usando il + nella parte inferiore del Navigatore di Breakpoint). Ciò si interromperà su qualsiasi eccezione (o è possibile impostare condizioni). Non so se questa scelta è nuova in 4.2 o se alla fine l'ho notato solo cercando di risolvere il problema dei simboli mancanti.

Una volta raggiunto questo punto di interruzione, è possibile utilizzare Debug Navigator per spostarsi nello stack di chiamate, esaminare le variabili, ecc. Come al solito.

Se si desidera uno stack di chiamate simbolizzato adatto per la copia / incolla o simili, gdb backtrace funzionerà bene da lì:

(gdb) bt
#0  0x01f84cf0 in objc_exception_throw ()
#1  0x019efced in -[NSObject doesNotRecognizeSelector:] ()

(eccetera)


3
Questo funziona perfettamente per me finora. Il debugger si interrompe ora sulla linea in crash, non è necessario il backtrace.
Tim

1
Questo funziona perfettamente anche per me. Grazie mille, stavo impazzendo senza questo breakpoint ...
William Denniss,

+1 perché ha funzionato. Non ti dà un messaggio di errore così bello che spiega il motivo dell'eccezione, ma è un inizio ...
Nicu Surdu

sei il mio HotD @WiseOldDuck.
Maverick,

Questo ripristina il comportamento previsto per me. NOTA: ricorda anche di aggiungere nuovamente questo punto di interruzione su nuovi progetti!
MechEthan,

46

C'è una nuova funzionalità nel debugger. È possibile impostare un punto di interruzione ogni volta che viene generata un'eccezione e interrompere l'esecuzione proprio lì, proprio come accadeva in 4.0.

Nel "Breakpoint Navigator", aggiungi un "Breakpoint di eccezione" e premi "Fine" nel popup delle opzioni.

È tutto!

PS: In alcuni casi sarebbe meglio rompere solo per le eccezioni dell'Obiettivo-C.


Sicuramente questa è la soluzione per me.
bradgonesurfing,

Questo è stato il problema per me. Un collega e io condividiamo lo stesso progetto Xcode e gli ho chiesto se stava avendo il problema, e non lo era. La differenza era che il suo progetto si stava rompendo su eccezioni obiettive-c (objc_exception_throw)
ferro di

Hai appena aiutato a trovare un bug non rintracciabile. Grazie mille. Ho cercato ovunque qualcosa del genere.
rjgonzo,

1
Funziona come un incantesimo! Era esattamente quello che stavo cercando, è meglio che aggiungere il Gestore eccezioni poiché l'aggiunta del Breakpoint può portarti esattamente dove è stata generata l'eccezione, il gestore eccezioni funziona ma ti dà solo un'idea.
im8bit

21

Ecco un'altra soluzione, non elegante come la precedente, ma se non hai aggiunto punti di interruzione o gestori di eccezioni, può essere solo una strada da percorrere.
Quando l'app si arresta in modo anomalo e ottieni il primo stack di chiamate raw (in numeri esadecimali), digita nella console Xcode info line *hex(non dimenticare l' identificatore stella ed 0xesadecimale), ad esempio:

(gdb) info line *0x2658
Line 15 of "path/to/file/main.m" starts at address 0x25f2 <main+50>
and ends at 0x267e <main+190>.

Se stai usando lldb , puoi digitareimage lookup -a hex (senza asterisco in questa situazione) e ottenere un output simile.

Con questo metodo, puoi attraversare dalla cima dello stack di lancio (ci saranno circa 5-7 propagatori di eccezioni di sistema) alla tua funzione che ha causato un arresto anomalo e determinare il file e la riga di codice esatti.

Inoltre, per un effetto simile puoi usare l'utilità atos nel terminale, basta digitare:

atos -o path/to/AplicationBundle.app/Executable 0xAdress1 0xAdress2 0xAdress3 ...

e ottieni una traccia simbolica dello stack (almeno per le funzioni che hanno simboli di debug). Questo metodo è più preferibile, poiché non è necessario per ogni chiamata di indirizzo info line, basta copiare gli indirizzi dall'output della console e incollarli nel terminale.


9

È possibile aggiungere un Breakpoint di eccezione (utilizzando il + nella parte inferiore del Navigatore di Breakpoint) e aggiungere l'azione bt ad esso (fare clic sul pulsante Aggiungi azione, selezionare Comando debugger, immettere "bt" nel campo di testo). Questo visualizzerà la traccia dello stack non appena viene generata un'eccezione.


6

Questo è un problema comune, non ottenere tracce di stack in 4.2. Puoi provare a scambiare tra LLDB e GDB per vedere se ottieni risultati migliori.

Invia una segnalazione di bug qui.

http://developer.apple.com/bugreporter/

MODIFICARE:

Credo che se torni a LLVM GCC 4.2 non vedrai che ciò accadrà. Tuttavia, potresti perdere funzionalità di cui hai bisogno.


Sì, ho provato a cambiare i compilatori, tuttavia il problema persiste. ma grazie comunque :)
cekisakurek,

Ha suggerito di cambiare debugger, non compilatori.
bames53,

1
Cordiali saluti: In questo caso, non ha nulla a che fare con la versione del compilatore o del debugger che si sta utilizzando. Questa è una modifica nell'output della console da iOS.
clarkcox3,

Interessante quante esperienze di questo variano - penso che ci siano alcuni problemi. Non sono riuscito a far arrestare il debugger sul punto di interruzione dell'eccezione. Il passaggio da GDB a LLDB ha risolto il problema.
Matt

6

Usa questo codice nella tua funzione principale:

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int retVal;
    @try {
        retVal = UIApplicationMain(argc, argv, nil, nil);
    }
    @catch (NSException *exception) {
        NSLog(@"CRASH: %@", exception);
        NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    }
    @finally {
        [pool release];
    }
    return retVal;
}

Questo non sembra funzionare con gli storyboard. 2012-06-04 20: 34: 52.211 Problemi [1944: 207] Il delegato dell'app deve implementare la proprietà window se desidera utilizzare un file storyboard principale. 2012-06-04 20: 34: 52.213 Problemi [1944: 207] Si prevede che le applicazioni dispongano di un controller di visualizzazione radice alla fine del lancio dell'applicazione
macasas

6

Al prompt della console di debug di Xcode digitare:

image lookup -a 0x1234

E ti mostrerà qualcosa di simile:

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202

Grazie, stavo davvero cercando questo. Sorprendente non ci sono scorciatoie per visualizzare l'intero "stack di chiamate del primo lancio" come stack di chiamate, poiché immagino che uno script lldb di Python possa essere facilmente scritto.
Ilya,

1

Riattivare 'Compile for Thumb' (configurazione di debug) ha funzionato per me.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.