322 Views
September 26, 24
スライド概要
デバッガの仕組みや、Go でどのように実装するのかを簡単に説明します。
Go でデバッガを自作する okarin 1
Go でデバッガを自作する 自己紹介 okarin (Kyota Okabe) 所属 ● 株式会社ハイヤールー エンジニアリング領域 ● バックエンド ● 認証・認可 ● (少しだけ)機械学習 Activities ● community: Ehime.go ● X: @okarin_dev 好きなもの ● ブロッコリー ● ランニング 2
Go でデバッガを自作する 今回話すこと ● プログラムを追跡可能にする仕組み ● ブレークポイントの仕組み ● Go で実装するには? 3
Go でデバッガを自作する プログラムを追跡可能にする仕組み ptrace によって子プロセスを追跡できる (※ Linux の場合) 4
Go でデバッガを自作する ブレークポイントの仕組み 命令の書き換え(※ x86-64 アーキテクチャの場合) 0x ** ** ** ** 0x ** ** ** ** 0x 48 83 ec 78 48 c7 44 24 0x cc 83 ec 78 48 c7 44 24 0x ** ** ** ** 0x ** ** ** ** 命令の先頭1バイトを 0xcc (INT3) に書き換えると、 その命令に達したタイミングで子プロセスは停止、それを親プロセスが検知できる ブレークポイント 5
Go でデバッガを自作する Go で実装するには? 使いやすいパッケージが すでに用意されている! ● ● ● sys/unix debug/dwarf debug/elf 6
Go でデバッガを自作する
コードの一例
breakpoint を設定するコード
●
(準)標準パッケージのおかげで書きやすい!
func (bp *Breakpoint) Enable() error {
_, err := sys.PtracePeekData(bp.pid, bp.addr, bp.originalInstruction)
if err != nil {
return err
}
data := binary.LittleEndian.Uint64(bp.originalInstruction)
// data & ^0xff => data & 11111111 … 11111111 00000000
newData := (data & ^uint64(0xff)) | Int3Instruction
newInstruction := make([]byte, 8)
binary.LittleEndian.PutUint64(newInstruction, newData)
_, err = sys.PtracePokeData(bp.pid, bp.addr, newInstruction)
if err != nil {
return err
}
}
bp.isEnabled = true
return nil
7
Go でデバッガを自作する まとめ ● ptrace でプログラムを追跡する ● ブレークポイントは 0xcc (INT3) で設定 ● Go は便利な(準)標準パッケージがあるのでデバッガを作りやすい 参考資料 ● ● Writing a Linux Debugger ptrace(2) - Linux manual page 8