hacking ruby with python

25
Hacking Ruby with Python @tyamadajp

Upload: taisuke-yamada

Post on 24-May-2015

2.033 views

Category:

Technology


5 download

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

Hacking Rubywith

Python

@tyamadajp

Page 2: Hacking Ruby with Python

光ある所、影があり

コードある所、闇がある

Page 3: Hacking Ruby with Python

闇の名は、バグ。

そしてバグを殺す者、

Page 4: Hacking Ruby with Python

Ruby Debugger

~僕と契約して闇デバッガになろうよ!~

Page 5: Hacking Ruby with Python

みなさんオススメのデバッガは?

0. p+? (?!)1. debug.rb? (旧型)2. ruby-debug? (普通)3. rb-trepanning? (新型)4. others?

#ベースの機能を生かした# JRuby, Rubinius 用のとかも#ありますよね

Page 6: Hacking Ruby with Python

・どこまでも覗ける・動いている状態を覗ける・あろうことか、手まで出せる

「言語仕様?そんなの関係ねぇ!」

「もし闇の住人がデバッガーの       解説ページを読んだら」

デバッガのいい所

Page 7: Hacking Ruby with Python

さて今宵のデバッガは・・・

Page 8: Hacking Ruby with Python

さて今宵のデバッガは・・・

GDB

Page 9: Hacking Ruby with Python

さて今宵のデバッガは・・・

TheGNUDebugger

Page 10: Hacking Ruby with Python

さて今宵のデバッガは・・・

… の Python 拡張

さて今宵のデバッガは・・・

Page 11: Hacking Ruby with Python

さて今宵のデバッガは・・・

GDB/Python

さて今宵のデバッガは・・・

明日の Ruby のために、今夜は Python

Page 12: Hacking Ruby with Python

なにそれこわい

Page 13: Hacking Ruby with Python

こわくないよ!> GDB/Python

1. GDB を 100% API control→ ブレークポイントの操作とか

2. GDB そのものも拡張 →新コマンド追加 / (gdb)...

 →簡易関数の追加 / $func(...)

 → print ハイジャック / pretty printer

Page 14: Hacking Ruby with Python

こんな感じ(実装例)

(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

それ $RUBY/.gdbinit でできるよ?

ええ、あるのですが・・・

・主力は内蔵 eval や dump 関数?

・なので展開能力が控えめ ( ぬるぽ避け? )

  (gdb) rp recv  T_CLASS: $1156 = (struct RClass *) 0x655310

      →ソース読解の道具が欲しかった      →自分でデコードするのがよい練習

Page 16: Hacking Ruby with Python

ぬるぽを恐れず何でも展開

(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

GDB script ではダメですか?

・ まともな制御構文がない → if else if else if else end end end

・ スコープ概念が(ほとんど)ない

・ 遅い。当人比で最大 100+倍以上

・ 限りなく貧弱なデータ操作機能とライブラリ

     「 GDB script がやられたか・・・」     「所詮あやつは言語以前の存在」

Page 18: Hacking Ruby with Python

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

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

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

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

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

おまけ: 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

おまけ: 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

まとめ

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/