Xcode / LLDB:スローされたばかりの例外に関する情報を取得するにはどうすればよいですか?


83

OK、ブレークポイントobjc_exception_throwがトリガーされたところを想像してみてください。デバッガープロンプトに座っていますが、例外オブジェクトに関する詳細情報を取得したいと思います。どこにありますか?


2
例外が発生したばかりであり、その説明はまだコンソールに出力されていないことを忘れないでください。
Karoy Lorentey 2010

この質問をチェックしてください:stackoverflow.com/questions/711650
Nikolai Fetissov 2010

回答:


162

例外オブジェクトは、最初の引数としてに渡されますobjc_exception_throw。LLDBは、正しい呼び出し規約で引数を参照するための$arg1..$argn変数を提供し、例外の詳細を簡単に出力できるようにします。

(lldb) po $arg1
(lldb) po [$arg1 name]
(lldb) po [$arg1 reason]

objc_exception_throwこれらのコマンドを実行する前に、必ずコールスタックでフレームを選択してください。これがステージで実行されることを確認するには、WWDC15セッションビデオの「高度なデバッグとアドレスサニタイザー」を参照してください。

古い情報

GDBを使用している場合、最初の引数を参照する構文は、実行しているアーキテクチャの呼び出し規約によって異なります。実際のiOSデバイスでデバッグしている場合、オブジェクトへのポインターはレジスターにありr0ます。印刷またはメッセージを送信するには、次の簡単な構文を使用します。

(gdb) po $r0
(gdb) po [$r0 name]
(gdb) po [$r0 reason]

iPhoneシミュレーターでは、すべての関数の引数がスタックに渡されるため、構文はかなりひどいものになります。それに到達するために私が構築できる最短の式は*(id *)($ebp + 8)です。苦痛を軽減するために、便利な変数を使用することをお勧めします。

(gdb) set $exception = *(id *)($ebp + 8)
(gdb) po $exception
(gdb) po [$exception name]
(gdb) po [$exception reason]

$exceptionコマンドリストをobjc_exception_throwブレークポイントに追加することにより、ブレークポイントがトリガーされるたびに自動的に設定することもできます。

(テストしたすべてのケースで、ブレークポイントがヒットしたときに例外オブジェクトがeaxedxレジスタにも存在していたことに注意してください。ただし、常にそうなるかどうかはわかりません。)

以下のコメントから追加:

lldb、用スタックフレームを選択objc_exception_throwして、次のコマンドを入力します。

(lldb) po *(id *)($esp + 4)

6
lldbでこれをどのように行うでしょうか?「エラー:「id」への参照があいまいです」というエラーが表示されます
offex 2012

2
この情報のソースを提供できますか?私はそれについてもっと読みたい
ジョアン・ヌネス

3
現在、プロローグの前に私のために、次の作品は、上のbreaingときobjc_exception_throw LLDBpo *(id *)($esp + 4)
wbyoung 2013年

7
これはうまくいきました!ただし、スタックフレーム0を選択するまで機能しませんでした。(objc_exception_throw)。
funroll 2013年

7
po $eaxシミュレーターでは、$r0デバイス上にあるときのペンダントとして機能します。
モンキーダム2013年

10

新しいシミュレーター(iOS 8、64ビット)の場合、例外フレームで使用するxcode 6 im: objc_exception_throw

po $rax

32ビット:

po $eax

ラックスとは何ですか?

Raxは、古いeaxを置き換える64ビットレジスタです。

すべてのレジスタを見つける方法は?

register read

ソースウィキペディア


うーん... Xcode 6.1では、次のようになります:(lldb)po $ raxエラー:マテリアライズできませんでした:レジスタraxの値を読み取ることができませんでした実行でエラーが発生し、PrepareToExecuteJITExpressionができませんでした
bradheintz

@bradheintzシミュレーターまたはデバイス?私は6.0.1でこれを試してみました
ジョアン・ヌネス

そのためのソースへのリンクを提供できますか?ありがとう!
クリスコノバー2014年

lldbに書いたばかりです:registerread。次に、この情報を使用して、例外フレームの最初のレジスタが例外メッセージを保持していることがわかります。
ジョアン・ヌネス

[OK]を私はいくつかのドキュメントを見つけた:RAXは、64-ビットのレジスタです:64ビットロングモードでは、あなたが64ビットレジスタを使用することができます(例えばRAX代わりにEAXの代わりに、EBXのRBXを、など。)
ジョアン・ヌネス

6

この記事の執筆時点で、この投稿は、lldb printexceptionに対するGoogleのトップヒットです。したがって、lldbとx86_64を説明するためにこの回答を追加しています。

を使用po $eaxして例外を見つけようとして失敗しましたerror: Couldn't materialize struct: Couldn't read eax (materialize)。以前の回答からのリンクされたドキュメントに記載されている他の試みも失敗しました。

重要なのは、最初objc_exception_throwにメインスレッドのフレームをクリックする必要があったことです。lldbはそのフレームで開始されません。

私の検索と次のすべての例で、このブログエントリは私にとってうまくいく方法で物事を説明した最初のものでした。それはより現代的で、2012年8月に投稿されました。


1

catchステートメントがある場合は、そこにブレークポイントを設定すると、その時点で例外オブジェクトを検査できます。

catchステートメントがない場合は、続行してください。

ターミナルに次のようなメッセージが表示されます。

キャッチされなかった例外 'NSInvalidArgumentException'が原因でアプリを終了しています、理由: ' * -[__ NSPlaceholderDictionary initWithObjects:forKeys:count:]:オブジェクトからnilオブジェクトを挿入しようとしています[0]'

ただし、アプリケーションが終了するとスタックトレースが失われるため、続行せずに検査する方法を探している可能性があります。

そのため、Fnordの答えが最善のように思えますが、LLDBで機能させることができませんでした。

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