memologue RSSフィード

書いている人

日記というよりは備忘録、ソフトウェア技術者の不定期メモ。あるいはバッドノウハウ集。プライベートで調査した細々した諸々のスナップショット。嘘が散りばめられています。ISO/IEC 14882(C++)とPOSIX, GCC, glibc, ELFの話ばかりで、WindowsやMacの話はありません。特に記載がなければLinux/x86とILP32が前提です。時間の経過と共に古い記事は埋もれてしまいます。検索エンジンから飛んできた場合は、ページ内検索をご利用いただくかgoogleキャッシュを閲覧してみてください。技術的な記事を書きためる場所として使っています。言及してもらえると喜びます。主要な記事の一覧を書いておきます:

にんきコンテンツ: [GCC] mainを一度も呼ばないばかりか蹂躙する / Binary2.0 Conference 2006 発表資料 / C++ で SICP / ついカッとなって実行バイナリにパッチ / hogetrace - 関数コールトレーサ

昔のPOSIX関係の記事: シグナルの送受に依存しない設計にしよう / シグナルハンドラで行ってよい処理を知ろう / マルチスレッドのプログラムでのforkはやめよう / スレッドの「非同期キャンセル」を行わない設計にしよう / スレッドの「遅延キャンセル」も出来る限り避けて通ろう / マルチスレッドプログラミングの「常識」を守ろう / C++でsynchronized methodを書くのは難しい / シグナルハンドラからのforkするのは安全か? / g++ の -fthreadsafe-statics ってオプション知ってます? / 非同期シグナルとanti-pattern / localtimeやstrtokは本当にスレッドセーフにできないのか / UNIXの規格について / マルチスレッドと共有変数 - volatile?なにそれ。 / type punning と strict aliasing / アセンブラで遊ぶ時に便利なgdb設定 / 最近の記事は一覧から

2007-11-05

[][] 50行straceもどき


すこし前に、straceコマンドもどきを50行くらいで書いてみたことがあるので、それを貼ってみまーす。いきなりコード。あ、C99です。

// strace_modoki.c:  Linux/x86専用です。x86_64カーネルでは-m32でコンパイルしても動きません。

#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <asm/user.h>
#include <asm/ptrace.h>

int main() {
  int i;
  static const char* syscallstr[1000] = {0};
  for(i = 0; i < 1000; ++i) syscallstr[i] = "???";

  syscallstr[0] = "restart_syscall";
  syscallstr[1] = "exit";
  syscallstr[2] = "fork";
  /* 略 */
  syscallstr[321] = "signalfd";
  syscallstr[322] = "timerfd";
  syscallstr[323] = "eventfd";

  if (!fork()) {
    // child
    ptrace(PTRACE_TRACEME, 0, 0, 0);
    execve("/bin/echo",
           (char *const []){ "/bin/echo", "123", NULL },
           (char *const []){ NULL });
    _exit(-1);
  } else {
    int st, in_syscall = 1; // うまく動かなかったら1を0にしてみてください :-)
    if (in_syscall) printf("enter execve() ");
    wait(&st); // wait for exec
    while (ptrace(PTRACE_SYSCALL, p, 0, 0) == 0) { // cont until syscall enter/leave
      wait(&st); // wait for syscall enter/leave
      if(WIFEXITED(st)) {
        puts("= ?"); break;
      }
      long orig_eax = ptrace(PTRACE_PEEKUSER, p, 4 * ORIG_EAX, 0);
      struct user_regs_struct regs;
      ptrace(PTRACE_GETREGS, p, 0, &regs);
      if (in_syscall == 0) {
        in_syscall = 1;
        printf("enter %s(0x%lx) ",
               (orig_eax >= 0 && orig_eax < 1000) ? syscallstr[orig_eax] : "???", regs.ebx);
      } else {
        in_syscall = 0;
        printf("= %ld\n", regs.eax);
      }
      fflush(stdout);
    }
  }
  return 0;
}

冒頭の syscallstr[nnn] = "xxx"; の部分は、/usr/include/asm/unistd.h をもとに、適当に変形して生成してください。余談ですがこのファイルをたまにのぞくと新規に追加されたシステムコールがわかって楽しいです。signalfdとか。エラーチェック他全部省略の手抜きコードです。うまく動かなかったらゴメンナサイ。


これを実行すると、まずfork()して子プロセスで /bin/echo 123 を実行し、親プロセスがその子の様子をptraceで観察します。出力はこんな感じになります。

% gcc -Wall -W strace_modoki.c
% ./a.out 
enter execve() = 0
enter brk(0x0) = 164818944
enter access(0x4bee8f) = -2
enter open(0x4bf077) = 3
enter fstat64(0x3) = 0
enter mmap2(0x0) = -1208172544
enter close(0x3) = 0
enter open(0xb7fd7a08) = 3
enter read(0x3) = 512
enter fstat64(0x3) = 0
enter mmap2(0x0) = -1208176640
enter mmap2(0x4c5000) = 5001216
enter mmap2(0x5ff000) = 6287360
enter mmap2(0x602000) = 6299648
enter close(0x3) = 0
enter mmap2(0x0) = -1208180736
enter set_thread_area(0xbfac95c4) = 0
enter mprotect(0x5ff000) = 0
enter mprotect(0x4c1000) = 0
enter munmap(0xb7fcc000) = 0
enter brk(0x0) = 164818944
enter brk(0x9d50000) = 164954112
enter fstat64(0x1) = 0
enter mmap2(0x0) = -1208119296
enter write(0x1) 123
= 4
enter close(0x1) = 0
enter munmap(0xb7fd9000) = 0
enter exit_group(0x0) = ?
% 

全くpretty printされていませんが、一応straceっぽい出力が得られています。ptraceの詳細については、man 2 ptraceや、2002年のこの記事あたりが参考になると思います。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証