Top Banner
Hacking Ruby with Python @tyamadajp
25

Hacking Ruby with Python

May 24, 2015

Download

Technology

Taisuke Yamada

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.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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/