mrubyでやってる話は前したけど、CRubyでも動いた。
I have ported BCC's hello_world.py into Ruby(MRI), and named it RbBCC!! I continue to porting the rest of functionalities. Check it out:https://t.co/wqQBlHXwhb pic.twitter.com/id4dglKQ8h
— Uchio KONDO 🔫 (@udzura) July 28, 2019
BCC が動作し、インストール済みのLinuxシステムで以下のコマンドでもうインストールできます。
$ gem install rbbcc --pre
デモのようにシステム全体の clone(2) をトレースして何かを出力する( Python版の hello_world.py 相当)例。こういうコードが動く。
require 'rbbcc' code = <<CLANG int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; } CLANG RbBCC::BCC.new(text: code).trace_print
実装方針の話
RbBCCでは1行も拡張コードを書いていない。マイナーな(すいません...)標準添付ライブラリ fiddle を全面的に使っている。
fiddleはもともと、 dl などと呼ばれていたライブラリの進化版で、 Python でいうと ctypes のように外部の拡張ライブラリを動的に読み、関数をRubyのメソッドとバインドしてくれる。
そもそものBCCの実装が、コア部分をC++で書いて、関数だけ出した libbcc.so を作り、それをPythonのctypesで呼び出しつつ、文字列操作やファイル読み出しのようなところをPythonに任せるという方針になっている。したがって、Rubyであればfiddleを使えば、RubyのコードだけでBCCの機能をポートできるはず? と思ってこちらも取り組んでみている。
require 'fiddle/import' module RbBCC module Clib extend Fiddle::Importer dlload "libbcc.so.0" extern 'void * bpf_module_create_c_from_string(char *, unsigned int, char **, int, long)' extern 'int bpf_num_functions(void *)' extern 'char * bpf_function_name(void *, int)' #... end end # こういうモジュールメソッドになる RbBCC::Clib.bpf_module_create_c_from_string("code", 0, [].pack("*p"), 0, 0) #...
char **
の引数のRuby側からの渡し方とか、実装方針が違うところもあるが、基本的にPythonのコードを逐語訳していけばできる。便利。
便利だが分量が多いので、ちょっとずつやっていく予定(その過程がそもそも勉強になるので良い)。こういうのの成果を松本でご覧に入れたいですね...。