Xcode 4.2デバッグはスタック呼び出しを象徴していません


140

iOS 5シミュレーター/デバイスでのXcode 4.2デバッグに問題があります。予想通り、次のコードがクラッシュします。

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

iOS 4では、16進数の有用なスタックトレースが表示されます。しかし、iOS 5では、次のようになります。

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

ありがとう。

回答:


256

私が試したところ、これを修正することはできませんでした(両方のコンパイラ、両方のデバッガなどを試しました)。

ただし、私は効果的な回避策を見つけました-独自の例外ハンドラーを作成します(これは他の理由でも役立ちます)。最初に、エラーを処理してコンソールに出力する関数を作成します(それを使用して実行する他のことも同様です)。

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

次に、例外ハンドラーをアプリデリゲートに追加します。

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

それでおしまい!

これが機能しない場合、考えられる理由2つだけです

  1. 何かがNSSetUncaughtExceptionHandler呼び出しを上書きしています(アプリ全体でハンドラーは1つしか存在できません)。たとえば、一部のサードパーティライブラリは独自のuncaughtExceptionHandlerを設定します。そのため、didFinishLaunchingWithOptions関数の最後に設定してみてください(またはサードパーティのライブラリを選択的に無効にしてください)。または、さらに良い方法として、シンボリックブレークポイントをオンNSSetUncaughtExceptionHandlerに設定して、誰が呼び出しているかをすばやく確認します。あなたがしたいかもしれないことは、別のものを追加するのではなく、現在のものを変更することです。
  2. 実際には例外は発生していません(たとえば、例外でEXC_BAD_ACCESSはありません。下記の@Erik Bのコメントを引用してください)

1
それを聞いてうれしい:)クラッシュログをファイルに書き込み、次回の起動時にユーザーに送信するように促すのが便利だと思います(リリースモードのみで、デバッグの邪魔にならないように)。これにより、すばらしいバグレポートを受け取ることができます...そして、ユーザーは問題が解決されていることを知っています:)
Zane Claes

2
これは機能していないようです- uncaughtExceptionHandlerルーチンが呼び出されることはありません。
Hot Licks

1
使い方をもっと詳しく教えてもらえますか?うまくいかないようです。
Danut Pralea、2011

1
かなり悲しいxCodeはこれを表示しません。
Authman Apatira 2012

1
とても有難い!Appleがこの種の基本的な機能をIDEに実装していないのは困惑しています。
devios1 2013年

110

例外ブレークポイントを追加する便利なオプションがあります(ブレークポイントナビゲーターの下部にある+を使用)。これにより、例外が発生すると中断されます(または条件を設定できます)。この選択が4.2の新機能なのか、それともシンボルの欠落の問題を回避しようとしているのについに気付いたのか、私にはわかりません。

このブレークポイントに到達すると、デバッグナビゲーターを使用して、通常どおり、コールスタックをナビゲートしたり、変数を調べたりできます。

コピー/貼り付けなどに適したシンボリックコールスタックが必要な場合、gdbバックトレースはそこから正常に機能します。

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

(等)


3
これまでのところ、これは完璧に機能します。デバッガーはクラッシュした行で停止します。バックトレースは必要ありません。
ティム

1
これも完璧に機能します。どうもありがとう、私はこのブレークポイントなしで気が狂っていました...
William Denniss

+1が機能しました。それはあなたに例外の理由を説明するそのような素晴らしいエラーメッセージを与えませんが、それは始まりです...
Nicu Surdu

あなたは私のHotD @WiseOldDuckです。
Maverick1

これにより、予想される動作が復元されます。注:新しいプロジェクトにこのブレークポイントを再度追加することも忘れないでください!
MechEthan 2012

46

デバッガーに新機能があります。例外がスローされたときはいつでもブレークポイントを設定し、4.0で発生していたのと同じように、そこで実行を停止することができます。

「ブレークポイントナビゲーター」で、「例外ブレークポイント」を追加し、オプションポップアップで「完了」を押します。

それで全部です!

PS:場合によっては、Objective-Cの例外に対してのみブレークする方が良いでしょう。


間違いなくこれが私にとっての解決策です。
Bradgonesurfing

これは私にとって問題でした。同僚と私は同じXcodeプロジェクトを共有していて、彼に問題があるのか​​どうかを尋ねましたが、問題はありませんでした。違いは、彼のプロジェクトがObjective-Cの例外(objc_exception_throw)に違反していたことです
horseshoe7

あなたは、追跡不可能なバグを見つけるのを助けました。どうもありがとうございます。私はこのようなものをどこでも探していました。
rjgonzo

1
これは魅力のように機能します!それはまさに私が探していたものでした。ブレークポイントを追加すると、例外がスローされた場所を正しく理解できるので、これは例外ハンドラを追加するよりも優れています。
im8bit

21

ここにもう1つのソリューションがありますが、以前ほどエレガントではありませんが、例外ブレークポイントまたはハンドラーを追加しなかった場合、それは1つの方法に過ぎません。
アプリがクラッシュし、最初のスローコールスタック(16進数)を取得したら、Xcodeコンソールに入力しますinfo line *hex(スターと0x16進数の指定子を忘れないでください)。次に例を示します。

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

lldbを使用している場合は、image lookup -a hex(この状況ではスターなしで)入力でき、同様の出力が得られます。

この方法を使用すると、スロースタックの最上部(約5〜7のシステム例外プロパゲーターがある)からクラッシュの原因となった関数までトラバースし、正確なファイルとコード行を特定できます。

また、同様の効果を得るには、ターミナルでatosユーティリティを使用できます。

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

シンボリックスタックトレースを取得します(少なくともデバッグシンボルがある関数の場合)。この方法の方が望ましいです。アドレスコールごとに行う必要がないためです。info line、コンソール出力からコピーしてターミナルに貼り付けるだけです。


9

例外ブレークポイントを追加し(ブレークポイントナビゲーターの下部にある+を使用)、アクション bt追加できます([アクションの追加]ボタンをクリックし、[デバッガーコマンド]を選択し、テキストフィールドに「bt」と入力します)。これにより、例外がスローされるとすぐにスタックトレースが表示されます。


6

これは、4.2ではスタックトレースを取得しない一般的な問題です。LLDBとGDBを交換して、より良い結果が得られるかどうかを確認できます。

ここにバグレポートを提出してください。

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

編集:

LLVM GCC 4.2にスワップバックすると、これが発生することはないと思います。ただし、必要な機能が失われる可能性があります。


はい、コンパイラを切り替えてみましたが、問題は解決しません。とにかくありがとう:)
cekisakurek '20年

彼はコンパイラーではなくデバッガーの切り替えを提案しました。
bames53 2011年

1
参考:この場合、使用しているコンパイラまたはデバッガのバージョンとは関係ありません。これは、iOSからのコンソール出力の変更です。
clarkcox3

これの経験がどれだけ異なるか興味深いです-いくつかの問題があると思います。デバッガーを例外ブレークポイントで停止させることができませんでした。GDBからLLDBに切り替えることで問題は解決しました。
Matt

6

このコードをメイン関数で使用します。

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

これはストーリーボードでは機能しないようです。2012-06-04 20:34:52.211の問題[1944:207]メインのストーリーボードファイルを使用する場合、アプリのデリゲートはウィンドウプロパティを実装する必要があります。2012-06-04 20:34:52.213の問題[1944:207]アプリケーションは、アプリケーションの起動の最後にルートビューコントローラーがあると予想されます
macasas

6

Xcodeのデバッグコンソールプロンプトで、次のように入力します。

image lookup -a 0x1234

そしてそれはあなたに次のようなものを示します:

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

ありがとう、本当に探していました。驚いたことに、「ファーストスローコールスタック」全体をコールスタックとして表示するショートカットはありません。Pythonlldbスクリプトは簡単に記述できると思います。
2015年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.