Skip to content

Instantly share code, notes, and snippets.

@sitano
Created October 18, 2021 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sitano/3bd9701d61037d1ac3bb6f7f1de6ca0c to your computer and use it in GitHub Desktop.
Save sitano/3bd9701d61037d1ac3bb6f7f1de6ca0c to your computer and use it in GitHub Desktop.
Example of using BPFTRACE with UPROBES for picking puts calls in Ruby VM
/**
*
* For a Ruby program:
*
* $ cat prog.rb
*
* Thread.new {
* while true
* puts "2222222222222222222222222222222222222222222222222222222222222222222222"
* sleep 0.2
* end
* }
*
* while true
* puts "1"
* sleep 0.2
* end
*
* $ ruby t.rb
*
* We can trace its internal as in the following example:
*
* $ sudo bpftrace prog.bt
*
*
**/
// VALUE
#define VALUE uintptr_t
// RBasic
struct RBasic {
VALUE flags;
const VALUE klass;
};
enum ruby_value_type {
RUBY_T_NONE = 0x00,
RUBY_T_OBJECT = 0x01,
RUBY_T_CLASS = 0x02,
RUBY_T_MODULE = 0x03,
RUBY_T_FLOAT = 0x04,
RUBY_T_STRING = 0x05,
// ...
RUBY_T_MASK = 0x1f
};
#define T_STRING RUBY_T_STRING
#define RB_BUILTIN_TYPE(x) (int32)(((struct RBasic*)(x))->flags & RUBY_T_MASK)
// RString
enum {
RUBY_FL_USHIFT = 12
};
enum {
RUBY_FL_USER0 = 0x1000,
RUBY_FL_USER1 = 0x2000,
RUBY_FL_USER2 = 0x4000,
RUBY_FL_USER3 = 0x8000,
RUBY_FL_USER4 = 0x10000,
RUBY_FL_USER5 = 0x20000,
RUBY_FL_USER6 = 0x40000,
RUBY_FL_USER17= 0x20000000
};
enum {
RSTRING_NOEMBED = RUBY_FL_USER1,
RSTRING_EMBED_LEN_MASK = (RUBY_FL_USER2|RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6),
RSTRING_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+2),
RSTRING_EMBED_LEN_MAX = (int)((sizeof(VALUE)*3)/sizeof(char)-1),
RSTRING_FSTR = RUBY_FL_USER17,
RSTRING_ENUM_END
};
struct RString {
struct RBasic basic;
union {
struct {
long len;
char *ptr;
union {
long capa;
VALUE shared;
} aux;
} heap;
char ary[RSTRING_EMBED_LEN_MAX + 1];
} as;
};
// #define RSTRING_EMBED_LEN(str) \
// (long)((RBASIC(str)->flags >> RSTRING_EMBED_LEN_SHIFT) & \
// (RSTRING_EMBED_LEN_MASK >> RSTRING_EMBED_LEN_SHIFT))
// #define RSTRING_LEN(str) \
// (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
// RSTRING_EMBED_LEN(str) : \
// RSTRING(str)->as.heap.len)
// #define RSTRING_PTR(str) \
// (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
// RSTRING(str)->as.ary : \
// RSTRING(str)->as.heap.ptr)
// #define RSTRING_END(str) \
// (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
// (RSTRING(str)->as.ary + RSTRING_EMBED_LEN(str)) : \
// (RSTRING(str)->as.heap.ptr + RSTRING(str)->as.heap.len))
// #define RSTRING_LENINT(str) rb_long2int(RSTRING_LEN(str))
// #define RSTRING_GETMEM(str, ptrvar, lenvar) \
// (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
// ((ptrvar) = RSTRING(str)->as.ary, (lenvar) = RSTRING_EMBED_LEN(str)) : \
// ((ptrvar) = RSTRING(str)->as.heap.ptr, (lenvar) = RSTRING(str)->as.heap.len))
enum {
RARRAY_EMBED_LEN_MAX = 3,
RARRAY_EMBED_FLAG = RUBY_FL_USER1,
/* RUBY_FL_USER2 is for ELTS_SHARED */
RARRAY_EMBED_LEN_MASK = (RUBY_FL_USER4|RUBY_FL_USER3),
RARRAY_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+3),
RARRAY_ENUM_END
};
uprobe:/home/sitano/.asdf/installs/ruby/2.4.10/lib/libruby.so:rb_io_puts /arg0 > 0/ {
// VALUE rb_io_puts(int argc, const VALUE *argv, VALUE out)
$val = *(arg1);
$flags = ((struct RBasic*)($val))->flags;
if (($flags & RUBY_T_MASK) == RUBY_T_STRING) {
$noembed = $flags & RSTRING_NOEMBED;
if (!$noembed) {
// RSTRING_PTR
$ptr0 = ((struct RString *)($val)) + sizeof(struct RBasic);
$str = (((struct RString *)($val))->as.ary);
// RSTRING_LEN
$len = ($flags >> RSTRING_EMBED_LEN_SHIFT) & (RSTRING_EMBED_LEN_MASK >> RSTRING_EMBED_LEN_SHIFT);
// OMG: https://github.com/iovisor/bpftrace/issues/553 - there is no & op
// OMG: char[] and int8 * are completelly diferrent types
// printf("[%d][%d]: %p of len %d: %s\n", pid, tid, (int64 *)((struct RString *)($val))->as.ary, $len, $str);
printf("[%d][%d]: %p of len %d: %s\n", pid, tid, $ptr0, $len, str($ptr0, $len));
} else {
// RSTRING_PTR
$ptr = ((struct RString *)($val))->as.heap.ptr;
// RSTRING_LEN
$len = ((struct RString *)($val))->as.heap.len;
printf("[%d][%d]: %p of len %d: %s\n", pid, tid, $ptr, $len, str($ptr, $len));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment