3

コンテキスト: 別のプラットフォーム用のインタープリターをプログラミングしています。これは、多くの場合、プログラムが任意の整数データからポインターをロードすることを意味します。分岐に関しては、次の命令のアドレスを読み取るためにすぐに逆参照しようとします。そのため、アドレスが無効な場合、しばらくしてからではなく、分岐命令のメソッド内でセグメンテーション違反が発生します。これにより、デバッグが容易になります。

ただし、これは私が望んでいたほど役に立ちません。そこでセグメンテーションフォルトが発生した場合、ダミーリードによってトリガーされたため、完全に回復できるはずなので、プログラムの命令ポインターをメソッドの先頭に戻し、セグメンテーションフォルトをリセットできるようにしたいと考えています。

LLDB にSIGSEGV、自分のプログラムに既に作成されている を無視するように指示できますか? どのシグナルが自分のプログラムに到達するかを決定するために使用できることはわかってprocess handle ...いますが、それはプロセスが現在処理している (または処理していない) シグナルには当てはまりません。

(それが不可能な場合でも、セグメンテーション違反で停止してプログラムに渡さないようにlldbに依頼することはできると思いますが、少なくともそれが可能かどうか知りたいです。)

4

1 に答える 1

4

EXC_BAD_ACCESS適切に配置するために回避しようとしていると思います。たとえば、このサンプルプログラムで dataptr を説明しているように聞こえます

#include <stdio.h>
int main ()
{
  void (*funcptr)(void) = 0;
  int *dataptr = 0;
  puts ("about to deref dataptr");
  printf ("%d\n", *dataptr);
  puts ("about to call through f ptr");
  funcptr();
  puts ("done");
  return 0;
}

dataptr呼び出しの逆参照で最初の EXC_BAD_ACCESS をヒットしprintfます。変数を有効な値に変更して、実行を続行できます。ここでの 1 つの秘訣は、コンパイル済みの例では変数dataptrがスタック上にあるということです。そのため、この時点で読み込まれているレジスタを設定して、それを乗り越える必要があります。ここでは、簡単な例として、このプログラムの有効なアドレスとしての開始アドレスを使用しています。-O0main()

* thread #1: tid = 0x1f03, 0x0000000100000eb6 a.out`main + 54 at a.c:7, stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
-> 7      printf ("%d\n", *dataptr);

(lldb) disass -c 1 --pc
a.out`main + 54 at a.c:7:
-> 0x100000eb6:  movl   (%rcx), %esi
(lldb) reg read rcx
     rcx = 0x0000000000000000
(lldb) p dataptr
(int *) $0 = 0x0000000000000000

(lldb) p dataptr = (int*) main
(int *) $1 = 0x0000000100000e80
(lldb) reg write rcx `$1`

(lldb) c
Process 77491 resuming
-443987883
about to call through f ptr
* thread #1: tid = 0x1f03, 0x0000000000000000, stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
    #0: 0x0000000000000000

NULL 関数ポインターを介して呼び出したため、停止しました。これを解きほぐすには、x86_64 ABI の知識が少し必要ですが、それほど難しいことではありません。PC を呼び出し元のリターン アドレスに設定し、スタックを 1 ワードポップすれば、元に戻ります。

(lldb) reg write pc `*(unsigned long long *)$sp`
(lldb) reg write sp `$sp + 8`
(lldb) c
Process 77522 resuming
done
Process 77522 exited with status = 0 (0x00000000) 

もちろん、これは非常に手動の調整であり、自動化するのは簡単ではありません。null 関数ポインタ deref を python 関数で表現し、lldb コマンドを追加して簡単に実行できますが、null データ ポインタ deref では、どのレジスタがアクセスされているかを知る必要があります。逆アセンブリ命令の巧妙なパターン マッチングによって、一般的なケースでは、いくつかの python 拡張機能を使用して同じことを行います。

それが役立つことを願っています。

于 2012-11-10T23:12:09.667 に答える