240 lines
5.3 KiB
Ruby
240 lines
5.3 KiB
Ruby
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
#
|
|
# Licence is LGPL, see LICENCE in the top-level directory
|
|
|
|
require 'test/unit'
|
|
require 'metasm'
|
|
|
|
class TestDynldr < Test::Unit::TestCase
|
|
def cp
|
|
@cp ||= Metasm::Ia32.new.new_cparser
|
|
end
|
|
|
|
def test_parse_c
|
|
assert_nothing_raised {
|
|
cp.parse("static int i_1=42; __stdcall __int64 foo_1(const char*);")
|
|
}
|
|
|
|
assert_kind_of(Metasm::C::Function, cp.toplevel.symbol['foo_1'].type)
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse("static extern int fu;") }
|
|
cp.readtok until cp.eos?
|
|
|
|
assert_nothing_raised { cp.parse("const volatile volatile const char const * const * blarg_0;") }
|
|
|
|
assert_nothing_raised { cp.parse("void *ptr = &ptr;") }
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse("void *ptr = ptr;") }
|
|
cp.readtok until cp.eos?
|
|
|
|
assert_nothing_raised { cp.parse("struct { int sz; } bla = { .sz = sizeof(bla) };") }
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse("signed unsigned int fu;") }
|
|
cp.readtok until cp.eos?
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse("long long long fu;") }
|
|
cp.readtok until cp.eos?
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse("void badarg(int i, int i) {}") }
|
|
cp.readtok until cp.eos?
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse("struct strun; union strun;") }
|
|
cp.readtok until cp.eos?
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse <<EOS }
|
|
asm <<EOA
|
|
foo
|
|
EOA
|
|
EOS
|
|
cp.readtok until cp.eos?
|
|
|
|
assert_nothing_raised { cp.parse <<EOS }
|
|
asm <<-EOA
|
|
foo
|
|
EOA
|
|
EOS
|
|
end
|
|
|
|
def test_struct
|
|
cp.parse <<EOS
|
|
struct foo_2 {
|
|
__int32 a;
|
|
__int8 b;
|
|
__int32 c;
|
|
__int8 d;
|
|
};
|
|
|
|
struct foo_3 {
|
|
__int8 a;
|
|
__int8 b;
|
|
__int16 c;
|
|
__int32 d;
|
|
};
|
|
|
|
struct foo_4 {
|
|
__int32 a;
|
|
__int8 b;
|
|
__int32 c;
|
|
__int8 d;
|
|
} __attribute__((packed));
|
|
|
|
union foo_5 {
|
|
__int64;
|
|
struct {
|
|
__int8;
|
|
__int8*;
|
|
};
|
|
struct {
|
|
__int16[8];
|
|
};
|
|
};
|
|
EOS
|
|
assert_equal(16, cp.sizeof(cp.toplevel.struct['foo_2']))
|
|
assert_equal(8, cp.toplevel.struct['foo_2'].offsetof(cp, 'c'))
|
|
assert_equal(8, cp.sizeof(cp.toplevel.struct['foo_3']))
|
|
assert_equal(10, cp.sizeof(cp.toplevel.struct['foo_4']))
|
|
assert_equal(4, cp.toplevel.struct['foo_4'].offsetof(cp, 'b'))
|
|
assert_equal(5, cp.toplevel.struct['foo_4'].offsetof(cp, 'c'))
|
|
assert_equal(16, cp.sizeof(cp.toplevel.struct['foo_5']))
|
|
|
|
assert_raise(Metasm::ParseError) { cp.parse("struct foo_3 { __int32 a; };") }
|
|
cp.readtok until cp.eos?
|
|
assert_nothing_raised { cp.parse("struct foo_3 { __int8 a; __int8 b; __int16 c; __int32 d; };") }
|
|
|
|
assert_nothing_raised {
|
|
cp.parse <<EOS
|
|
struct scop { int i; };
|
|
|
|
void func1(void) {
|
|
struct scop { __int64 j; __int64 z; };
|
|
struct scop s;
|
|
s.j = 0;
|
|
}
|
|
|
|
void func2(void) {
|
|
struct scop s;
|
|
s.i = 0;
|
|
}
|
|
EOS
|
|
}
|
|
end
|
|
|
|
def test_bitfields
|
|
cp.parse <<EOS
|
|
struct foo_bits {
|
|
__int32 f0:4;
|
|
__int32 :0;
|
|
__int32 f1:4;
|
|
__int32 f2:4;
|
|
__int8 f3;
|
|
__int32 f4:4;
|
|
__int32 f5:30;
|
|
};
|
|
|
|
struct foo_n_bits {
|
|
struct foo_bits;
|
|
};
|
|
|
|
struct foo2_bits {
|
|
__int64 f0:30;
|
|
__int64 f1:30;
|
|
__int64 f2:30;
|
|
};
|
|
|
|
struct foo3_bits {
|
|
__int16 f0:8;
|
|
__int16 f1:4;
|
|
__int16 f2:1;
|
|
};
|
|
EOS
|
|
st = cp.toplevel.struct['foo_bits']
|
|
assert_equal(20, cp.sizeof(st))
|
|
assert_equal([0, 4], st.bitoffsetof(cp, 'f1'))
|
|
assert_equal([4, 4], st.bitoffsetof(cp, 'f2'))
|
|
assert_equal(8, st.offsetof(cp, 'f3'))
|
|
assert_equal(12, st.offsetof(cp, 'f4'))
|
|
assert_equal([0, 30], st.bitoffsetof(cp, 'f5'))
|
|
|
|
st = cp.toplevel.struct['foo_n_bits']
|
|
assert_equal(20, cp.sizeof(st))
|
|
assert_equal([0, 4], st.bitoffsetof(cp, 'f1'))
|
|
assert_equal([4, 4], st.bitoffsetof(cp, 'f2'))
|
|
assert_equal(8, st.offsetof(cp, 'f3'))
|
|
assert_equal(12, st.offsetof(cp, 'f4'))
|
|
assert_equal([0, 30], st.bitoffsetof(cp, 'f5'))
|
|
|
|
st = cp.toplevel.struct['foo2_bits']
|
|
assert_equal([0, 30], st.bitoffsetof(cp, 'f0'))
|
|
assert_equal([30, 30], st.bitoffsetof(cp, 'f1'))
|
|
assert_equal([0, 30], st.bitoffsetof(cp, 'f2'))
|
|
|
|
st = cp.toplevel.struct['foo3_bits']
|
|
assert_equal(2, cp.sizeof(st))
|
|
end
|
|
|
|
def test_allocstruct
|
|
cp.parse <<EOS
|
|
struct foo_outer {
|
|
int i;
|
|
struct {
|
|
int j;
|
|
int k;
|
|
} inner;
|
|
};
|
|
EOS
|
|
s = cp.alloc_c_struct('foo_outer', :i => :size)
|
|
assert_equal(12, s.sizeof)
|
|
assert_equal(12, s.i)
|
|
assert_raise(RuntimeError) { s.l = 42 }
|
|
assert_nothing_raised { s.j = 0x12345678 }
|
|
assert_nothing_raised { s.inner.k = 0x3333_3333 }
|
|
assert_equal(4, s.inner.stroff)
|
|
assert_equal("0C0000007856341233333333", s.str.unpack('H*')[0].upcase)
|
|
end
|
|
|
|
def test_cmpstruct
|
|
st = <<EOS
|
|
struct foo {
|
|
struct foo *p;
|
|
int i;
|
|
};
|
|
|
|
struct s1 {
|
|
struct s2 *p;
|
|
};
|
|
|
|
struct s2 {
|
|
struct s1 *p;
|
|
};
|
|
EOS
|
|
cp.parse st
|
|
cp.parse <<EOS
|
|
struct t1 {
|
|
struct t2 *pt;
|
|
};
|
|
struct t2 {
|
|
struct t1 *pt;
|
|
};
|
|
EOS
|
|
|
|
cp2 = Metasm::Ia32.new.new_cparser
|
|
cp2.parse(st)
|
|
cp2.parse <<EOS
|
|
struct t1 {
|
|
struct t2 *pt;
|
|
};
|
|
struct t2 {
|
|
struct t3 *pt;
|
|
};
|
|
struct t3 {
|
|
struct t1 *pt;
|
|
};
|
|
EOS
|
|
assert_equal(true, cp.toplevel.struct['foo'] == cp2.toplevel.struct['foo'])
|
|
assert_equal(true, cp.toplevel.struct['s1'].compare_deep(cp2.toplevel.struct['s1']))
|
|
assert_equal(true, cp.toplevel.struct['t1'] == cp2.toplevel.struct['t1']) # expected failure
|
|
assert_equal(false, !!cp.toplevel.struct['t1'].compare_deep(cp2.toplevel.struct['t1']))
|
|
end
|
|
end
|