Más contenido relacionado La actualidad más candente (19) Similar a Hacking Ruby with Python (20) Más de Taisuke Yamada (20) Hacking Ruby with Python5. みなさんオススメのデバッガは?
0. p+? (?!)
1. debug.rb? (旧型)
2. ruby-debug? (普通)
3. rb-trepanning? (新型)
4. others?
#ベースの機能を生かした
# JRuby, Rubinius 用のとかも
#ありますよね
13. こわくないよ!> GDB/Python
1. GDB を 100% API control
→ ブレークポイントの操作とか
2. GDB そのものも拡張
→新コマンド追加 / (gdb)...
→簡易関数の追加 / $func(...)
→ print ハイジャック / pretty printer
14. こんな感じ(実装例)
(gdb) p self
$299 = (struct RTypedData *) 0x64b2c0,
type=iseq ($300), data=0x731ee0 ($301)
(gdb) pp self
$302 = (struct RTypedData *) 0x64b2c0,
type=iseq ($303), data=0x731ee0 ($304)
$305 = (const rb_data_type_t *) 0x7ffff7dbe780
$306 = (rb_iseq_t *) 0x731ee0, <compiled>:3,
type=ISEQ_TYPE_TOP
・・・まあ色々デコードしてくれます
16. ぬるぽを恐れず何でも展開
(gdb) pp recv
$1158 = (struct RClass *) 0x655310 [Time]
dump: {basic = {flags = 2, klass = 6640360},
ptr=0x6e4e20, m_tbl=0x6e4e40, iv_index_tbl=0x0}
m_tbl: +, -, <=>, _dump, asctime, ctime, …
(gdb) pp ruby_current_thread->cfp->iseq 2
$1072 = (rb_iseq_t *) 0x75c9c0, MAIN,
/home/tai/tarai.rb:1(p=0x70a260/$1073,
l=0x70a260/$1074)
line#0003: VALUE ラップもの、 ID 、
$1075 putstring NODE 、 rb_iseq_t 、 rb_vm_t...
自動で型判定し p or pp で
$1076 getclassvariable
… 中身を徹底表示
17. GDB script ではダメですか?
・ まともな制御構文がない
→ if else if else if else end end end
・ スコープ概念が(ほとんど)ない
・ 遅い。当人比で最大 100+ 倍以上
・ 限りなく貧弱なデータ操作機能とライブラリ
「 GDB script がやられたか・・・」
「所詮あやつは言語以前の存在」
18. GDB Python API - basic
import gdb
# vmは gdb.Value オブジェクトだが rb_vm_t* の型を保持
vm = gdb.parse_and_eval(“ruby_current_vm”)
# これも gdb.Value オブジェクトだが、 rb_thread_t* の型を維持
th = vm['running_thread']
# いわゆる構造体ダンプ :(gdb) p *ruby_current_vm
print(vm.dereference())
# ポインタ演算したいときには char* にしたり
pointer_op(th.cast(gdb.lookup_type(“char”).pointer()))
# CLI 側で参照できるよう $ や $N に戻したりもできる
gdb.execute(“p (%s)%ld” % (th.type, long(th)))
gdb.execute(“set $foo = %ld” % long(th))
19. GDB Command – extending gdb
import gdb
class HelloCommand(gdb.Command):
"""Sample GDB command in Python"""
def __init__(self):
super(self.__class__, self).__init__(
"hello-cmd", gdb.COMMAND_OBSCURE)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
print("arg is [%s]" % ", ".join(args))
HelloCommand()
拡張1つにクラスを1つ
※ ロードは (gdb) python execfile(“hello.py”) などで
20. GDB Command – easy way
import gdb
@gdbcommand(“hello-cmd“)
def hello(*args):
"""
Sample GDB command in Python
Usage: hello-cmd args
"""
print("arg is [%s]" % ", ".join(args))
バイト数 50% カット!
21. GDB Command – easy way, impl
def gdbcommand(*args):
"""Turns decorated function into GDB command"""
opts = [args[0], gdb.COMMAND_OBSCURE] #FIXME
def wrap(func):
name = opts[0] or func.func_name
def init(self):
super(self.__class__, self).__init__(name, *opts[1:])
def invoke(self, arg, from_tty):
func(*gdb.string_to_argv(arg))
type("", (gdb.Command,), {
'__doc__': func.__doc__, '__init__': init, 'invoke': invoke,
})()
return func
return wrap デコレータ、 Ruby にも
本気で欲しくなったり
※ スライドに収めるため機能とコードをカットしています。バグってたらごめんなさい
22. GDB Pretty Printer
class HelloPrinter(object):
"""Print (hello_t *) type"""
def __init__(self, val): self.val = val
# 表示する文字列又は gdb.Value を返す。後者の場合は
# 再度 pretty-printing 処理が試みられる。以下はダミー。
def to_string(self): return "hogehoge"
# 表示ヒント。 "array", "map", "string" のいずれかを返す
def display_hint(self): return "string"
# カスタムプリンタが反応できるようチェッカを登録
def ckval(gv):
if gv.type == gdb.lookup_type("hello_t").pointer():
return HelloPrinter(gv)
return None print 以外にも、あらゆる
gdb.pretty_printers.append(ckval) 表示処理に適用される
23. おまけ: Ruby と Python の狂演
$ rlwrap gdb -q -readnow --args ./ruby1.9.1 tarai.rb
(gdb) b vm_exec
(gdb) run
(gdb) python sys.argv = [“gdb”] # GDB 側の漏れ対応
(gdb) python execfile("/usr/bin/ipython")
IPython 0.10.2 -- An enhanced Interactive Python.
In [1]: from gdb import *
In [2]: vm = parse_and_eval("ruby_current_vm")
In [3]: vm
Out[3]: <gdb.Value object at 0x207bb70>
In [4]: p vm['main_thread'].type
struct rb_thread_struct *
補完処理が壊れたり、単に GDB/Python スクリプト
書くよりバグ率高いですが、変態的な可能性を感じる
24. おまけ: gdb.rb – GDB/Ruby in Py*
https://github.com/tmm1/gdb.rb
「 gdb hooks for MRI/REE (and some for YARV) 」
(gdb) b vm_exec if $interactive == 0
(gdb) run
(gdb) set $interactive = 1 #自己呼び出しのブロック防止
(gdb) python execfile("ruby-gdb.py")
(gdb) ruby eval Thread.list
[#<Thread:0x00000000650cc0 run>]
(gdb) ruby objects
HEAPS 24
SLOTS 9816 実は金曜日に発見して
LIVE 2717 (27.68%) かなりへこんだ。
FREE 7099 (72.32%) Ruby 内部の機能をフルに
使って自分自身をデバッグ
complex 1 (0.04%)
bignum 2 (0.07%)
25. まとめ
1. Ruby のデバッグ・学習に使ってみた
2. GDB/Python は強力なツール
3.正直わけがわからないよ!
「明日の Ruby のために、今夜は Python 」
参考文献:
・ sourceware.org/gdb/onlinedocs/gdb/Python-API.html
・ sourceware.org/gdb/wiki/PythonGdbTutorial
・ gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python/