5

リテールビルドでコアダンプを分析するには、多くobjdumpの場合、特定のモジュールとソースを相互に関連付ける必要があります。通常、関数が非常に複雑な場合、アセンブリダンプをソースと関連付けるのは面倒です。assembly listing今日、私は1つの特定のモジュール(コンパイルオプションを使用)を作成しようとしましたが-S、アセンブリまたは何らかの相関関係を持つインターリーブソースが表示されることを期待していました。残念ながら、リストは相互に関連付けるのに十分なほど友好的ではなかったので、私は疑問に思っていました

  • クラッシュの場所を特定できるコアダンプが与えられた
  • objdump失敗したモジュールのアセンブリリストを再コンパイルして
  • -Sオプション付きモジュール。

ソースと1対1で対応することは可能ですか?

例として、アセンブリリストは次のように表示されます。

.LBE7923:
        .loc 2 4863 0
        movq    %rdi, %r14
        movl    %esi, %r12d
        movl    696(%rsp), %r15d
        movq    704(%rsp), %rbp
.LBB7924:
        .loc 2 4880 0
        testq   %rdx, %rdx
        je      .L2680
.LVL2123:
        testl   %ecx, %ecx
        jle     .L2680
        movslq  %ecx,%rax
        .loc 2 4882 0
        testl   %r15d, %r15d
        .loc 2 4880 0
        leaq    (%rax,%rax,4), %rax
        leaq    -40(%rdx,%rax,8), %rdx
        movq    %rdx, 64(%rsp)

.LVL2123しかし、のようなラベルとのようなディレクティブを解釈する方法を理解できませんでした.loc 2 4863 0

示されている回答のように、アセンブリソースを読み、シンボル(関数呼び出し、分岐、returnステートメントなど)に基づいてパターンを直感的に判断することが、私が一般的に行っていることです。私はそれが機能しないことを否定していませんが、関数がかなり関与している場合、アセンブリリストのページを読むのは苦痛であり、関数がインライン化されるかオプティマイザが単に投げられたために、ほとんど一致しないリストになってしまうことがよくあります好きなようにコード。どれだけ効率的に見えるかValgrind最適化されたバイナリを処理し、Windows WinDBGで最適化されたバイナリを処理する方法について、私が見逃していることがあります。だから私はコンパイラの出力から始めて、それを使って相関させます。私のコンパイラがバイナリのマングリングを担当している場合、ソースとの相関方法を言うのが最善の人ですが、残念ながらそれはあまり役に立たず、.loc本当に誤解を招く恐れがあります。残念ながら、私はさまざまなプラットフォーム間で再現不可能なダンプを読み通さなければならないことが多く、WinDBGを介したWindowsミニダンプのデバッグとLinuxコアダンプのデバッグに費やす時間が最も少なくなっています。私はそれが私が物事を正しくやっていないかもしれないけれども、私はこの質問を思いついた。

4

3 に答える 3

4

ソースと1対1で対応することは可能ですか?

A:いいえ、すべての最適化が無効になっていない限り。コンパイラーは最初に行ごとにいくつかの命令のグループ(または命令のようなもの)を発行する場合がありますが、オプティマイザーは次にそれらを並べ替え、分割、融合し、通常は完全に変更します。


リリースコードを逆アセンブルする場合は、コードと明確な論理的関係を持つ必要がある命令を確認します。例えば、

.LBB7924:
        .loc 2 4880 0
        testq   %rdx, %rdx
        je      .L2680

がゼロの場合は分岐のように見え、%rdx4880行目から取得されます。行を見つけ、テストされている変数を特定し、現在に割り当てられていることをメモし%rdxます。

.LVL2123:
        testl   %ecx, %ecx
        jle     .L2680

OK、このテストとブランチは同じターゲットを持っているので、次に来るものは何でも知っていて%rdx%ecx両方ともゼロ以外です。元のコードは次のように構成されている可能性があります。

if (a && b) {

または多分それは:

if (!a || !b) {

オプティマイザーは2つのブランチを並べ替えました...

これで、元のコードとうまく一致させることができる構造ができました。また、レジスタの割り当てを把握することもできます。たとえば、テスト対象が構造体のデータメンバーであることがわかっている場合は、逆方向に読み取って%rdx、メモリからロードされた場所を確認します。固定オフセットから他のレジスタにロードされましたか?もしそうなら、そのレジスタはおそらくオブジェクトアドレスです。

幸運を!

于 2012-05-02T14:20:38.617 に答える
4

ディレクティブは.locあなたが探しているものです。これらは、行#4863、4880などを示しています。ソースと最適化されたアセンブラの間に完全なマッピングはありません(これが、4880が複数回表示される理由です)。しかし.loc、それがファイルのどこにあるかを知る方法です。構文は次のとおりです。

.loc <file> <line> <column>
于 2012-05-02T12:56:23.283 に答える
1

システムライブラリに対して静的にリンクしない限り、デバッグシンボルがなくても、バイナリにはシンボル名があります。これは、リンクされているシステムライブラリ関数の名前です。

これらは、コード内のどこにいるかを絞り込むのに役立つことがよくあります。たとえば、関数foo()でopen()を呼び出してからioctl()を呼び出し、read()を呼び出す直前にクラッシュする場合は、fooのソースでそのポイントを簡単に見つけることができます。(さらに言えば、ダンプは必要ないかもしれません-Linuxでは、ltraceまたはstraceを使用してライブラリおよびシステム関数に関連するクラッシュ発生の記録を取得できます)

ただし、一部のバイナリ形式では、バイナリの他の場所にある小さなラッパーを介してライブラリ関数に間接参照される場合があることに注意してください。多くの場合、ダンプには、プログラムフローの呼び出しのアドレスに関連するシンボリック名情報が含まれています。ただし、そうでない場合でも、バイナリ内のアドレスの範囲によってこれらの外部リンケージラッパーを認識できます。1つを見つけたら、そのコードを見つけて、リンク先の外部関数を特定できます。

しかし、他の人が述べているように、ソースコードとそれが役立つほど頻繁にクラッシュするシステムがある場合、通常、デバッグシンボルを使用して再構築するか、ログ出力を挿入してより有用なクラッシュレコードを取得するのが最善の策です。

于 2012-05-02T14:56:47.040 に答える