hacking ruby with python
DESCRIPTION
Short introduction of GDB/Python, with actual examples for debugging and (sort of) running Ruby-as-a-debugger-of-oneself on top of it. This was prepared for YamiRubyKaigi 2011 (Darkness of RubyKaigi2011), but unfortunately gave up doing actual presentation due to too many pages.TRANSCRIPT
![Page 1: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/1.jpg)
Hacking Rubywith
Python
@tyamadajp
![Page 2: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/2.jpg)
光ある所、影があり
コードある所、闇がある
![Page 3: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/3.jpg)
闇の名は、バグ。
そしてバグを殺す者、
![Page 4: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/4.jpg)
Ruby Debugger
~僕と契約して闇デバッガになろうよ!~
![Page 5: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/5.jpg)
みなさんオススメのデバッガは?
0. p+? (?!)1. debug.rb? (旧型)2. ruby-debug? (普通)3. rb-trepanning? (新型)4. others?
#ベースの機能を生かした# JRuby, Rubinius 用のとかも#ありますよね
![Page 6: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/6.jpg)
・どこまでも覗ける・動いている状態を覗ける・あろうことか、手まで出せる
「言語仕様?そんなの関係ねぇ!」
「もし闇の住人がデバッガーの 解説ページを読んだら」
デバッガのいい所
![Page 7: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/7.jpg)
さて今宵のデバッガは・・・
![Page 8: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/8.jpg)
さて今宵のデバッガは・・・
GDB
![Page 9: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/9.jpg)
さて今宵のデバッガは・・・
TheGNUDebugger
![Page 10: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/10.jpg)
さて今宵のデバッガは・・・
… の Python 拡張
さて今宵のデバッガは・・・
![Page 11: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/11.jpg)
さて今宵のデバッガは・・・
GDB/Python
さて今宵のデバッガは・・・
明日の Ruby のために、今夜は Python
![Page 12: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/12.jpg)
なにそれこわい
![Page 13: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/13.jpg)
こわくないよ!> GDB/Python
1. GDB を 100% API control→ ブレークポイントの操作とか
2. GDB そのものも拡張 →新コマンド追加 / (gdb)...
→簡易関数の追加 / $func(...)
→ print ハイジャック / pretty printer
![Page 14: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/14.jpg)
こんな感じ(実装例)
(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
・・・まあ色々デコードしてくれます
![Page 15: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/15.jpg)
それ $RUBY/.gdbinit でできるよ?
ええ、あるのですが・・・
・主力は内蔵 eval や dump 関数?
・なので展開能力が控えめ ( ぬるぽ避け? )
(gdb) rp recv T_CLASS: $1156 = (struct RClass *) 0x655310
→ソース読解の道具が欲しかった →自分でデコードするのがよい練習
![Page 16: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/16.jpg)
ぬるぽを恐れず何でも展開
(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: $1075 putstring $1076 getclassvariable …
VALUE ラップもの、 ID 、NODE 、 rb_iseq_t 、 rb_vm_t...自動で型判定し p or pp で中身を徹底表示
![Page 17: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/17.jpg)
GDB script ではダメですか?
・ まともな制御構文がない → if else if else if else end end end
・ スコープ概念が(ほとんど)ない
・ 遅い。当人比で最大 100+倍以上
・ 限りなく貧弱なデータ操作機能とライブラリ
「 GDB script がやられたか・・・」 「所詮あやつは言語以前の存在」
![Page 18: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/18.jpg)
GDB Python API - basicimport 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_vmprint(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))
![Page 19: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/19.jpg)
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()
※ロードは (gdb) python execfile(“hello.py”) などで
拡張1つにクラスを1つ
![Page 20: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/20.jpg)
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%カット!
![Page 21: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/21.jpg)
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 にも
本気で欲しくなったり
※スライドに収めるため機能とコードをカットしています。バグってたらごめんなさい
![Page 22: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/22.jpg)
GDB Pretty Printerclass 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 Nonegdb.pretty_printers.append(ckval)
print以外にも、あらゆる表示処理に適用される
![Page 23: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/23.jpg)
おまけ: 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]: vmOut[3]: <gdb.Value object at 0x207bb70>In [4]: p vm['main_thread'].typestruct rb_thread_struct *
補完処理が壊れたり、単に GDB/Python スクリプト書くよりバグ率高いですが、変態的な可能性を感じる
![Page 24: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/24.jpg)
おまけ: 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%)
complex 1 (0.04%) bignum 2 (0.07%)
実は金曜日に発見してかなりへこんだ。Ruby 内部の機能をフルに使って自分自身をデバッグ
![Page 25: Hacking Ruby with Python](https://reader034.vdocuments.site/reader034/viewer/2022051211/55615408d8b42adb6b8b54a7/html5/thumbnails/25.jpg)
まとめ
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/