Das Xcode 4.2-Debug symbolisiert keinen Stapelaufruf

140

Ich habe ein Problem mit dem Debuggen von Xcode 4.2 in einem iOS 5-Simulator / Gerät. Der folgende Code stürzt erwartungsgemäß ab:

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

In iOS 4 erhalte ich eine nützliche Stapelverfolgung von Hex-Zahlen. Aber in iOS 5 gibt es mir nur:

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

Vielen Dank.

cekisakurek
quelle

Antworten:

256

Nichts, was ich versucht habe, würde dies beheben (beide Compiler, beide Debugger usw.). Nach dem Upgrade von XCode für das iOS 5-Update schienen keine Stack-Traces zu funktionieren.

Ich habe jedoch eine effektive Problemumgehung gefunden - das Erstellen eines eigenen Ausnahmebehandlers (was auch aus anderen Gründen nützlich ist). Erstellen Sie zunächst eine Funktion, die den Fehler behandelt und an die Konsole ausgibt (sowie alles, was Sie sonst noch damit tun möchten):

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

Fügen Sie als Nächstes den Ausnahmebehandler zu Ihrem App-Delegaten hinzu:

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

Das ist es!

Wenn dies nicht funktioniert, gibt es nur zwei mögliche Gründe :

  1. Etwas überschreibt Ihren NSSetUncaughtExceptionHandlerAnruf (es kann nur einen Handler für Ihre gesamte App geben). Beispielsweise setzen einige Bibliotheken von Drittanbietern ihren eigenen uncaughtExceptionHandler. Versuchen Sie also, es am ENDE Ihrer didFinishLaunchingWithOptionsFunktion einzustellen (oder Bibliotheken von Drittanbietern selektiv zu deaktivieren). Oder noch besser, setzen Sie einen symbolischen Haltepunkt, NSSetUncaughtExceptionHandlerum schnell zu sehen, wer ihn anruft. Möglicherweise möchten Sie Ihre aktuelle Version ändern, anstatt eine weitere hinzuzufügen.
  2. Sie stoßen tatsächlich nicht auf eine Ausnahme (zum Beispiel EXC_BAD_ACCESSist dies keine Ausnahme; siehe die Kommentare von @Erik B unten)
Zane Claes
quelle
1
Freut mich zu hören :) Ich finde es nützlich, das Absturzprotokoll in eine Datei zu schreiben und den Benutzer aufzufordern, es beim nächsten Start zu senden (nur im Release-Modus, um das Debuggen nicht zu behindern). Auf diese Weise kann ich großartige Fehlerberichte erhalten ... und die Benutzer wissen, dass ihr Problem behoben wird :)
Zane Claes,
2
Dies scheint nicht zu funktionieren - die uncaughtExceptionHandlerRoutine wird nie aufgerufen.
Hot Licks
1
Können Sie bitte genauer sagen, wie man es benutzt? Es scheint bei mir nicht zu funktionieren.
Danut Pralea
1
Ziemlich traurig, dass xCode dies für uns nicht anzeigt.
Authman Apatira
1
Sehr geschätzt! Es ist verwirrend, dass Apple diese Art von rudimentären Funktionen nicht in die IDE implementiert.
Devios1
110

Es gibt eine nützliche Option zum Hinzufügen eines Ausnahme-Haltepunkts (mit dem + am unteren Rand des Haltepunkt-Navigators). Dies wird bei jeder Ausnahme unterbrochen (oder Sie können Bedingungen festlegen). Ich weiß nicht, ob diese Auswahl in 4.2 neu ist oder ob ich erst endlich bemerkt habe, dass sie versucht hat, das Problem der fehlenden Symbole zu umgehen.

Sobald Sie diesen Haltepunkt erreicht haben, können Sie mit dem Debug-Navigator wie gewohnt im Aufrufstapel navigieren, Variablen untersuchen usw.

Wenn Sie einen symbolisierten Aufrufstapel wünschen, der zum Kopieren / Einfügen oder dergleichen geeignet ist, funktioniert gdb backtrace von dort aus einwandfrei:

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

(etc)

WiseOldDuck
quelle
3
Das funktioniert bisher perfekt für mich. Der Debugger hält jetzt auf der Absturzlinie an, ohne dass die Rückverfolgung erforderlich ist.
Tim
1
Das funktioniert auch bei mir perfekt. Vielen Dank, ich wurde ohne diesen Haltepunkt verrückt ...
William Denniss
+1 dafür hat es funktioniert. Es gibt Ihnen nicht so eine nette Fehlermeldung, die den Grund der Ausnahme erklärt, aber es ist ein Anfang ...
Nicu Surdu
Du bist mein HotD @WiseOldDuck.
Maverick1st
Dies stellt das erwartete Verhalten für mich wieder her. HINWEIS: Denken Sie auch daran, diesen Haltepunkt bei neuen Projekten erneut hinzuzufügen!
MechEthan
46

Es gibt eine neue Funktion im Debugger. Sie können einen Haltepunkt festlegen, wenn eine Ausnahme ausgelöst wird, und die Ausführung genau dort stoppen, wie es früher bei 4.0 der Fall war.

Fügen Sie im "Breakpoint Navigator" einen "Exception Breakpoint" hinzu und drücken Sie einfach "Done" im Options-Popup.

Das ist alles!

PS: In einigen Fällen wäre es besser, nur für Objective-C-Ausnahmen zu brechen.

Pedro
quelle
Auf jeden Fall ist dies die Lösung für mich.
Bradgonesurfing
Das war das Problem für mich. Ein Kollege und ich teilen dasselbe Xcode-Projekt und ich fragte ihn, ob er das Problem habe und er nicht. Der Unterschied war, dass sein Projekt auf Ziel-c-Ausnahmen (objc_exception_throw) brach
Hufeisen7
Sie haben gerade geholfen, einen nicht auffindbaren Fehler zu finden. Ich danke dir sehr. Ich habe überall nach so etwas gesucht.
Rjgonzo
1
Das funktioniert wie ein Zauber! Genau das habe ich gesucht. Dies ist besser als das Hinzufügen des Ausnahmehandlers, da Sie durch Hinzufügen des Haltepunkts genau dorthin gelangen können, wo die Ausnahme ausgelöst wurde. Der Ausnahmehandler funktioniert, gibt Ihnen jedoch nur eine Idee.
Im8bit
21

Hier ist eine weitere Lösung, die nicht so elegant wie zuvor ist. Wenn Sie jedoch keine Ausnahme-Haltepunkte oder Handler hinzugefügt haben, kann dies nur ein Weg sein.
Wenn die App abstürzt und Sie Ihren rohen First-Throw-Call-Stack (in Hex-Zahlen) erhalten, geben Sie Folgendes in die Xcode-Konsole ein info line *hex(Stern- und 0xHex-Spezifizierer nicht vergessen ), zum Beispiel:

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

Wenn Sie lldb verwenden , können Sie eingebenimage lookup -a hex (in dieser Situation ohne Stern), und Sie erhalten eine ähnliche Ausgabe.

Mit dieser Methode können Sie vom oberen Rand des Wurfstapels (es werden ungefähr 5-7 Systemausnahme-Propagatoren vorhanden sein) zu Ihrer Funktion wechseln, die einen Absturz verursacht hat, und die genaue Datei und Codezeile bestimmen.

Für einen ähnlichen Effekt können Sie auch das Dienstprogramm atos im Terminal verwenden. Geben Sie einfach Folgendes ein:

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

und Sie erhalten eine symbolisierte Stapelverfolgung (zumindest für Funktionen, für die Sie Debug-Symbole haben). Diese Methode ist vorzuziehen, da Sie nicht für jeden Adressaufruf info linenur Adressen aus der Konsolenausgabe kopieren und in das Terminal einfügen müssen.

Alexander
quelle
9

Sie können einen Ausnahme-Haltepunkt hinzufügen (mit dem + am unteren Rand des Haltepunkt-Navigators) und die Aktion hinzufügen bt (klicken Sie auf die Schaltfläche Aktion hinzufügen , wählen Sie Debugger-Befehl, geben Sie "bt" in das Textfeld ein). Dadurch wird die Stapelverfolgung angezeigt, sobald eine Ausnahme ausgelöst wird.

MonsieurDart
quelle
6

Dies ist ein häufiges Problem, da in 4.2 keine Stapelspuren abgerufen werden. Sie können versuchen, zwischen LLDB und GDB zu wechseln, um bessere Ergebnisse zu erzielen.

Reichen Sie hier einen Fehlerbericht ein.

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

BEARBEITEN:

Ich glaube, wenn Sie zu LLVM GCC 4.2 zurückkehren, werden Sie dies nicht sehen. Möglicherweise verlieren Sie jedoch die benötigten Funktionen.

logancautrell
quelle
Ja, ich habe versucht, die Compiler zu wechseln, aber das Problem bleibt bestehen. aber trotzdem danke :)
cekisakurek
Er schlug vor, Debugger zu wechseln, nicht Compiler.
Bames53
1
Zu Ihrer Information: In diesem Fall hat dies nichts mit der Version des Compilers oder Debuggers zu tun, den Sie verwenden. Dies ist eine Änderung in der Konsolenausgabe von iOS.
Clarkcox3
Interessant, wie unterschiedlich die Erfahrungen damit sind - ich denke, es gibt ein paar Probleme. Ich konnte den Debugger nicht dazu bringen, am Ausnahme-Haltepunkt anzuhalten. Der Wechsel von GDB zu LLDB löste das Problem.
Matt
6

Verwenden Sie diesen Code in Ihrer Hauptfunktion:

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;
}
Wilson Lin
quelle
Dies scheint mit Storyboards nicht zu funktionieren. 2012-06-04 20: 34: 52.211 Probleme [1944: 207] Der App-Delegat muss die Fenstereigenschaft implementieren, wenn er eine Haupt-Storyboard-Datei verwenden möchte. 2012-06-04 20: 34: 52.213 Probleme [1944: 207] Es wird erwartet, dass Anwendungen am Ende des Anwendungsstarts einen Root-View-Controller haben
Macasas
6

Geben Sie an der Eingabeaufforderung der Debug-Konsole von Xcode Folgendes ein:

image lookup -a 0x1234

Und es wird Ihnen so etwas zeigen wie:

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202
Matt Connolly
quelle
Danke, ich habe wirklich danach gesucht. Überraschenderweise gibt es keine Verknüpfung zum Anzeigen des gesamten "First Throw Call Stack" als Call Stack, da ich denke, dass ein Python lldb-Skript einfach geschrieben werden kann.
Ilya
1

Das Wiedereinschalten von 'Compile for Thumb' (Debug-Konfiguration) hat bei mir funktioniert.

Bradweiser86
quelle