10

私のプログラムは、dietlibc で静的にコンパイルされています。ubuntu x64 (-m32 フラグを使用して x86 用にコンパイル) でコンパイルされ、centos x86 で実行されます。

コンパイルされたサイズはわずか約 100KB です。-ggdb3 でコンパイルし、最適化フラグはありません。

私のプログラムは、signal.h を使用して SIGSEGV シグナルを処理してから、abort() を呼び出します。

プログラムは数日間問題なく動作しますが、セグメンテーション違反が発生することがあります。これは、私が理解できない奇妙なバックトレースを取得したときです。

username@ubuntu:~/Desktop$ gdb -c core.28569 プログラム名
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 以降
これはフリー ソフトウェアです。自由に変更して再配布してください。
法律で許可されている範囲で、保証はありません。「コピーを表示」と入力します
詳細については、「保証を表示する」を参照してください。
この GDB は、「--host=x86_64-linux-gnu --target=i386-linux-gnu」として構成されました。
バグ報告の手順については、次を参照してください。
...
program-name からシンボルを読み取っています...完了しました。
[新しいスレッド 28569]
コアは「プログラム名」によって生成されました。
プログラムはシグナル 6 で終了しました。中止されました。
#0 0x00914410 in __kernel_vsyscall ()
gdb をデバッグするための環境をセットアップします。
関数 "internal_error" が定義されていません。
今後の共有ライブラリのロード時にブレークポイントを保留にしますか? (y または [n]) [N と答えた; 端末からではない入力]
関数 "info_command" が定義されていません。
今後の共有ライブラリのロード時にブレークポイントを保留にしますか? (y または [n]) [N と答えた; 端末からではない入力]
.gdbinit:8: ソースのコマンド ファイルにエラーがあります:
引数が必要です (1 つ以上のブレークポイント番号)。
(gdb) ところで
#0 0x00914410 in __kernel_vsyscall ()
シンボル読み取り中、不完全な CFI データ。0x914411 の未指定のレジスタ (eax など)。
#1 __unified_syscall()で0x0804d7f4
#2 0xbf8966c0 in ?? ()
#3  
#4 0x2054454e in ?? ()
#5 0x20524c43 in ?? ()
#6 0x2e352e33 in ?? ()
#7 0x32373033 in ?? ()
#8 0x2e203b39 in ?? ()
#9 0x2054454e で ?? ()
#10 0x20524c43 in ?? ()
#11 0x2e302e33 in ?? ()
#12 0x32373033 in ?? ()
#13 0x4d203b39 in ?? ()
#14 0x61696465 in ?? ()
#15 0x6e654320 in ?? ()
#16 0x20726574 in ?? ()
#17 0x36204350 in ?? ()
#18 0x203b302e in ?? ()
#19 0x54454e2e in ?? ()
#20 0x43302e34 in ?? ()
#21 0x00000029 in ?? ()
#22 0xbf8989a8 in ?? ()
バックトレースが停止しました: このフレームの内側にある前のフレーム (スタックが破損していますか?)
(gdb) bt フル
#0 0x00914410 in __kernel_vsyscall ()
シンボル テーブル情報がありません。
#1 __unified_syscall()で0x0804d7f4
シンボル テーブル情報がありません。
#2 0xbf8966c0 in ?? ()
シンボル テーブル情報がありません。
#3  
シンボル テーブル情報がありません。
#4 0x2054454e in ?? ()
シンボル テーブル情報がありません。
#5 0x20524c43 in ?? ()
シンボル テーブル情報がありません。
#6 0x2e352e33 in ?? ()
シンボル テーブル情報がありません。
#7 0x32373033 in ?? ()
シンボル テーブル情報がありません。
#8 0x2e203b39 in ?? ()
シンボル テーブル情報がありません。
#9 0x2054454e で ?? ()
シンボル テーブル情報がありません。
#10 0x20524c43 in ?? ()
シンボル テーブル情報がありません。
#11 0x2e302e33 in ?? ()
シンボル テーブル情報がありません。
#12 0x32373033 in ?? ()
シンボル テーブル情報がありません。
#13 0x4d203b39 in ?? ()
シンボル テーブル情報がありません。
#14 0x61696465 in ?? ()
シンボル テーブル情報がありません。
#15 0x6e654320 in ?? ()
シンボル テーブル情報がありません。
#16 0x20726574 in ?? ()
シンボル テーブル情報がありません。
#17 0x36204350 in ?? ()
シンボル テーブル情報がありません。
#18 0x203b302e in ?? ()
シンボル テーブル情報がありません。
#19 0x54454e2e in ?? ()
シンボル テーブル情報がありません。
#20 0x43302e34 in ?? ()
シンボル テーブル情報がありません。
#21 0x00000029 in ?? ()
シンボル テーブル情報がありません。
#22 0xbf8989a8 in ?? ()
シンボル テーブル情報がありません。
バックトレースが停止しました: このフレームの内側にある前のフレーム (スタックが破損していますか?)
(gdb) やめる
4

2 に答える 2

16

スタックオーバーランです。

#4  0x2054454e in ?? ()

「TEN」や「NET」などのテキストのように見えます

#5  0x20524c43 in ?? ()

" RLC" または "CLR "

等々。

アドレスをテキストであるかのように扱います。このテキストがスタックを上書きする場所を特定できるかどうかを確認してください。

于 2011-03-13T15:26:12.527 に答える
6

実際、スタック トレースは非常に理解しやすいものです。

  • どこかで SIGSEGV を取得しました。
  • あなたのシグナルハンドラーはそれがすることを何でもしてから呼び出されましたabort()
  • raise(2)システムコールを発行したのは、呼び出して__unified_syscall()

GDB でスタック トレースが取得されない理由は、

  • __unified_syscallアセンブリで実装され、
  • フレームポインタを使用せず、
  • cfiそこから巻き戻す方法を説明する適切なディレクティブがありません。

これは、実際には非常に簡単に修正できる、dietlibc のバグだと思います。この(テストされていない)パッチで修正されるかどうかを確認してください:

--- dietlibc-0.31/i386/unified.S.orig   2011-03-13 10:16:23.000000000 -0700
+++ dietlibc-0.31/i386/unified.S    2011-03-13 10:21:32.000000000 -0700
@@ -31,8 +31,14 @@ __unified_syscall:
    movzbl  %al, %eax
 .L1:
    push    %edi
+        cfi_adjust_cfa_offset (4)
+        cfi_rel_offset (edi, 0)
    push    %esi
+        cfi_adjust_cfa_offset (4)
+        cfi_rel_offset (esi, 0)
    push    %ebx
+        cfi_adjust_cfa_offset (4)
+        cfi_rel_offset (ebx, 0)
    movl    %esp,%edi
    /* we use movl instead of pop because otherwise a signal would
       destroy the stack frame and crash the program, although it
@@ -61,8 +67,11 @@ __unified_syscall:
 #endif
 .Lnoerror:
    pop %ebx
+        cfi_adjust_cfa_offset (-4)
    pop %esi
+        cfi_adjust_cfa_offset (-4)
    pop %edi
+        cfi_adjust_cfa_offset (-4)

 /* here we go and "reuse" the return for weak-void functions */
 #include "dietuglyweaks.h"

Dietlibc を再構築できない場合、またはパッチが正しくない場合でも、スタック トレースをより適切に分析できる可能性があります。私が知る限り、__unified_syscall触れません%ebp。したがって、次のようにすると、適切なスタック トレースを取得できる場合があります。

define xbt
  set $xbp = (void **)$arg0
  while 1
    x/2a $xbp
    set $xbp = (void **)$xbp[0]
  end
end

xbt $ebp

注:動作する場合、信号フレームxbtの周りの雑草に入る可能性がありSIGSEGVます (そのフレームはフレーム ポインターも使用しません)。これにより、完全なガベージが発生するか、1 つまたは 2 つのフレームがスキップされる可能性があります (これは、SIGSEGV発生したフレームとまったく同じです)。

したがって、dietlibc に適切なアンワインド記述子を取得する方がはるかに優れています。

于 2011-03-13T17:31:44.883 に答える