156 lines
3.8 KiB
C
156 lines
3.8 KiB
C
#ifdef __ELF__
|
|
asm .pt_gnu_stack rw;
|
|
#endif
|
|
typedef uintptr_t VALUE;
|
|
static VALUE const_File;
|
|
static VALUE const_LinuxHeap;
|
|
VALUE rb_ary_new(void);
|
|
VALUE rb_ary_push(VALUE, VALUE);
|
|
extern VALUE *rb_cObject __attribute__((import));
|
|
VALUE rb_const_get(VALUE, VALUE);
|
|
void rb_define_method(VALUE, char*, VALUE(*)(), int);
|
|
VALUE rb_funcall(VALUE recv, unsigned int id, int nargs, ...);
|
|
VALUE rb_gv_get(const char*);
|
|
VALUE rb_intern(char*);
|
|
VALUE rb_ivar_get(VALUE, unsigned int);
|
|
VALUE rb_iv_get(VALUE, char*);
|
|
void *rb_method_node(VALUE, unsigned int);
|
|
VALUE rb_obj_as_string(VALUE);
|
|
VALUE rb_str_append(VALUE, VALUE);
|
|
VALUE rb_str_cat2(VALUE, const char*);
|
|
VALUE rb_str_new2(const char*);
|
|
VALUE rb_hash_aset(VALUE, VALUE, VALUE);
|
|
VALUE rb_hash_aref(VALUE, VALUE);
|
|
VALUE rb_uint2inum(VALUE);
|
|
VALUE rb_num2ulong(VALUE);
|
|
char *rb_string_value_ptr(VALUE*);
|
|
|
|
|
|
int printf(char*, ...);
|
|
|
|
static VALUE heap_entry(void *heap, VALUE idx, VALUE psz)
|
|
{
|
|
if (psz == 4)
|
|
return (VALUE)(((__int32*)heap)[idx]);
|
|
return (VALUE)(((__int64*)heap)[idx]);
|
|
}
|
|
|
|
static VALUE m_LinuxHeap23scan_heap(VALUE self, VALUE vbase, VALUE vlen, VALUE ar)
|
|
{
|
|
VALUE *heap;
|
|
VALUE chunks;
|
|
VALUE base = rb_num2ulong(vbase);
|
|
VALUE len = vlen >> 1;
|
|
VALUE sz, clen;
|
|
VALUE page;
|
|
VALUE psz = rb_iv_get(self, "@ptsz") >> 1;
|
|
VALUE ptr = 0;
|
|
|
|
chunks = rb_iv_get(self, "@chunks");
|
|
page = rb_funcall(self, rb_intern("pagecache"), 2, vbase, vlen);
|
|
heap = rb_string_value_ptr(&page);
|
|
|
|
sz = heap_entry(heap, 1, psz);
|
|
if (heap_entry(heap, 0, psz) != 0 || (sz & 1) != 1)
|
|
return 4;
|
|
|
|
base += 8;
|
|
|
|
for (;;) {
|
|
clen = sz & -8;
|
|
ptr += clen/psz;
|
|
if (ptr >= len/psz || clen == 0)
|
|
break;
|
|
|
|
sz = heap_entry(heap, ptr+1, psz);
|
|
if (sz & 1)
|
|
rb_hash_aset(chunks, rb_uint2inum(base), ((clen-psz)<<1)|1);
|
|
base += clen;
|
|
}
|
|
|
|
rb_funcall(self, rb_intern("del_fastbin"), 1, ar);
|
|
|
|
return 4;
|
|
}
|
|
|
|
|
|
|
|
static VALUE m_LinuxHeap23scan_heap_xr(VALUE self, VALUE vbase, VALUE vlen)
|
|
{
|
|
VALUE *heap;
|
|
VALUE chunks, xrchunksto, xrchunksfrom;
|
|
VALUE psz = rb_iv_get(self, "@ptsz") >> 1;
|
|
VALUE base = rb_num2ulong(vbase) + 2*psz;
|
|
VALUE len = vlen >> 1;
|
|
VALUE sz, clen;
|
|
VALUE page;
|
|
|
|
chunks = rb_iv_get(self, "@chunks");
|
|
xrchunksto = rb_iv_get(self, "@xrchunksto");
|
|
xrchunksfrom = rb_iv_get(self, "@xrchunksfrom");
|
|
page = rb_funcall(self, rb_intern("pagecache"), 2, vbase, vlen);
|
|
heap = rb_string_value_ptr(&page);
|
|
|
|
sz = heap_entry(heap, 1, psz);
|
|
if (heap_entry(heap, 0, psz) != 0 || (sz & 1) != 1)
|
|
return 4;
|
|
|
|
/* re-walk the heap, simpler than iterating over @chunks */
|
|
VALUE ptr = 0;
|
|
VALUE ptr0, ptrl;
|
|
for (;;) {
|
|
clen = sz & -8;
|
|
ptr0 = ptr+2;
|
|
ptrl = clen/psz-1;
|
|
ptr += clen/psz;
|
|
if (ptr >= len/psz || clen == 0)
|
|
break;
|
|
|
|
sz = heap_entry(heap, ptr+1, psz);
|
|
if ((sz & 1) &&
|
|
((rb_hash_aref(chunks, rb_uint2inum(base))|4) != 4)) {
|
|
VALUE tabto = 0;
|
|
VALUE tabfrom;
|
|
while (ptrl--) {
|
|
VALUE p = heap_entry(heap, ptr0++, psz);
|
|
//if (p == base) // ignore self-references
|
|
// continue;
|
|
if ((rb_hash_aref(chunks, rb_uint2inum(p))|4) != 4) {
|
|
if (!tabto) {
|
|
tabto = rb_ary_new();
|
|
rb_hash_aset(xrchunksto, rb_uint2inum(base), tabto);
|
|
}
|
|
rb_ary_push(tabto, rb_uint2inum(p));
|
|
|
|
tabfrom = rb_hash_aref(xrchunksfrom, rb_uint2inum(p));
|
|
if ((tabfrom|4) == 4) {
|
|
tabfrom = rb_ary_new();
|
|
rb_hash_aset(xrchunksfrom, rb_uint2inum(p), tabfrom);
|
|
}
|
|
rb_ary_push(tabfrom, rb_uint2inum(base));
|
|
}
|
|
}
|
|
}
|
|
base += clen;
|
|
}
|
|
return 4;
|
|
}
|
|
|
|
|
|
|
|
static void do_init_once(void)
|
|
{
|
|
const_LinuxHeap = rb_const_get(*rb_cObject, rb_intern("Metasm"));
|
|
const_LinuxHeap = rb_const_get(const_LinuxHeap, rb_intern("LinuxHeap"));
|
|
rb_define_method(const_LinuxHeap, "scan_heap", m_LinuxHeap23scan_heap, 3);
|
|
rb_define_method(const_LinuxHeap, "scan_heap_xr", m_LinuxHeap23scan_heap_xr, 2);
|
|
}
|
|
|
|
|
|
|
|
int Init_compiled_heapscan_lin __attribute__((export))(void)
|
|
{
|
|
do_init_once();
|
|
return 0;
|
|
}
|