ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

BCCの hello_world.py 相当がCRubyでも動いた

udzura.hatenablog.jp

mrubyでやってる話は前したけど、CRubyでも動いた。

github.com

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 を全面的に使っている。

docs.ruby-lang.org

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のコードを逐語訳していけばできる。便利。

便利だが分量が多いので、ちょっとずつやっていく予定(その過程がそもそも勉強になるので良い)。こういうのの成果を松本でご覧に入れたいですね...。