class Metasm::C::AllocCStruct

this maps a C structure from a C parser to a ruby String struct members are accessed through obj obj.fldname is an alias

Attributes

cp[RW]

str is a reference to the underlying ruby String stroff is the offset from the start of this string (non-nul for nested structs) cp is a reference to the C::Parser struct to the C::Union/Struct/Array sizeof is the byte size of the C struct

sizeof[W]
str[RW]

str is a reference to the underlying ruby String stroff is the offset from the start of this string (non-nul for nested structs) cp is a reference to the C::Parser struct to the C::Union/Struct/Array sizeof is the byte size of the C struct

stroff[RW]

str is a reference to the underlying ruby String stroff is the offset from the start of this string (non-nul for nested structs) cp is a reference to the C::Parser struct to the C::Union/Struct/Array sizeof is the byte size of the C struct

struct[RW]

str is a reference to the underlying ruby String stroff is the offset from the start of this string (non-nul for nested structs) cp is a reference to the C::Parser struct to the C::Union/Struct/Array sizeof is the byte size of the C struct

Public Class Methods

new(cp, struct, str=nil, stroff=0) click to toggle source
# File metasm/parse_c.rb, line 2966
def initialize(cp, struct, str=nil, stroff=0)
        @cp, @struct = cp, struct
        @str = str || [0].pack('C')*sizeof
        @stroff = stroff
end

Public Instance Methods

[](*a) click to toggle source
# File metasm/parse_c.rb, line 2976
def [](*a)
        if @struct.kind_of? C::Array and a.length == 1 and @struct.length and a[0].kind_of? Integer
                i = a[0]
                raise "#{i} out of bounds 0...#{@struct.length}" if  i < 0 or i >= @struct.length
                off = @stroff + i*@cp.sizeof(@struct.type)
                return @cp.decode_c_value(@str, @struct.type, off)
        end

        return @str[@stroff..-1][*a] if a.length != 1
        a = a.first
        return @str[@stroff..-1][a] if not a.kind_of? Symbol and not a.kind_of? String and not a.kind_of? C::Variable
        f = a
        raise "#{a.inspect} not a member" if not f.kind_of? C::Variable and not f = @struct.findmember(a.to_s, true)
        a = f.name || f
        off = @stroff + @struct.offsetof(@cp, a)
        if bf = @struct.bitoffsetof(@cp, a)
                ft = C::BaseType.new((bf[0] + bf[1] > 32) ? :__int64 : :__int32)
                v = @cp.decode_c_value(@str, ft, off)
                (v >> bf[0]) & ((1 << bf[1])-1)
        else
                @cp.decode_c_value(@str, f, off)
        end
end
[]=(*a) click to toggle source
# File metasm/parse_c.rb, line 3000
def []=(*a)
        if @struct.kind_of? C::Array and a.length == 2 and @struct.length and a[0].kind_of? Integer
                i = a[0]
                raise "#{i} out of bounds 0...#{@struct.length}" if  i < 0 or i >= @struct.length
                off = @stroff + i*@cp.sizeof(@struct.type)
                val = @cp.encode_c_value(@struct.type, a[1])
                @str[off, val.length] = val
                return
        end

        if not a.first.kind_of? Symbol and not a.first.kind_of? String and not a.first.kind_of? C::Variable
                # patch @str[@stroff..-1] like a string
                # so we must find the intended start offset, and add @stroff to it
                if @stroff != 0
                        case a.first
                        when Range
                                if a.first.begin >= 0
                                        a[0] = ::Range.new(a[0].begin+@stroff, a[0].end+@stroff, a[0].exclude_end?)
                                else raise 'no can do, use positive index'
                                end
                        when Integer
                                if a.first >= 0
                                        a[0] += @stroff
                                else raise 'no can do, use positive index'
                                end
                        else raise 'no can do'
                        end
                end

                return @str.send(:'[]=', *a)        # XXX *should* work...
        end

        a, val = a
        f = a
        raise "#{a.inspect} not a struct member" if not f.kind_of? C::Variable and not f = @struct.findmember(a.to_s, true)
        a = f.name || f
        val = sizeof if val == :size
        off = @stroff + @struct.offsetof(@cp, a)

        if bf = @struct.bitoffsetof(@cp, a)
                raise "only Integers supported in bitfield #{a}, got #{val.inspect}" if not val.kind_of?(::Integer)
                # struct { int i:8; };  =>  size 8 or 32 ?
                ft = C::BaseType.new((bf[0] + bf[1] > 32) ? :__int64 : :__int32)
                mask = ((1 << bf[1]) - 1) << bf[0]
                preval = @cp.decode_c_value(@str, ft, off)
                val = (preval & ~mask) | ((val << bf[0]) & mask)
                f = ft
        end

        val = @cp.encode_c_value(f, val)
        @str[off, val.length] = val
end
method_missing(on, *a) click to toggle source

virtual accessors to members struct.foo is aliased to struct, struct.foo = 42 aliased to struct = 42

Calls superclass method
# File metasm/parse_c.rb, line 3056
def method_missing(on, *a)
        n = on.to_s
        if n[-1] == ?=
                send :[]=, n[0...-1], *a
        else
                super(on, *a) if not @struct.kind_of?(C::Union) or not @struct.findmember(n, true)
                send :[], n, *a
        end
end
sizeof() click to toggle source
# File metasm/parse_c.rb, line 2972
def sizeof
        @sizeof ||= @cp.sizeof(@struct)
end
to_array() click to toggle source
# File metasm/parse_c.rb, line 3115
def to_array
        raise NoMethodError, "Not an Array" if not @struct.kind_of?(C::Array)
        ary = []
        @struct.length.times { |i| ary << self[i] }
        ary
end
to_s(off=nil, maxdepth=500) click to toggle source
# File metasm/parse_c.rb, line 3066
def to_s(off=nil, maxdepth=500)
        return '{ /* ... */ }' if maxdepth <= 0
        str = ['']
        if @struct.kind_of?(C::Array)
                str.last << "#{@struct.type} x[#{@struct.length}] = " if not off
                mlist = (0...@struct.length)
                fldoff = mlist.inject({}) { |h, i| h.update i => i*@cp.sizeof(@struct.type) }
        elsif @struct.kind_of?(C::Struct)
                str.last << "struct #{@struct.name || '_'} x = " if not off
                @struct.update_member_cache(@cp) if not @struct.fldlist
                fldoff = @struct.fldoffset
                mlist = @struct.members.map { |m| m.name || m }
        else
                str.last << "union #{@struct.name || '_'} x = " if not off
                mlist = @struct.members.map { |m| m.name || m }
        end
        str.last << '{'
        mlist.each { |k|
                if k.kind_of? Variable      # anonymous member
                        curoff = off.to_i + @struct.offsetof(@cp, k)
                        val = self[k]
                        k = '?'
                else
                        curoff = off.to_i + (fldoff ? fldoff[k].to_i : 0)
                        val = self[k]
                end
                if val.kind_of?(::Integer)
                        if val >= 0x100
                                val = '0x%X,   // +%x' % [val, curoff]
                        elsif val <= -0x100
                                val = '-0x%X,   // +%x' % [-val, curoff]
                        else
                                val = '%d,   // +%x' % [val, curoff]
                        end
                elsif val.kind_of? AllocCStruct
                        val = val.to_s(curoff, maxdepth-1)
                elsif not val
                        val = 'NULL,   // +%x' % curoff # pointer with NULL value
                else
                        val = val.to_s.sub(/$/, ',   // +%x' % curoff)
                end
                val = val.gsub("\n", "\n\t")
                str << "\t#{k.kind_of?(::Integer) ? "[#{k}]" : ".#{k}"} = #{val}"
        }
        str << '}'
        str.last << (off ? ',' : ';')
        str.join("\n")
end
to_strz() click to toggle source
# File metasm/parse_c.rb, line 3122
def to_strz
        raise NoMethodError, "Not an Array" if not @struct.kind_of?(C::Array)
        a = to_array
        a[a.index(0)..-1] = [] if a.index(0)
        a.pack('C*')
end