class Metasm::C::Union

Attributes

backtrace[RW]
bits[RW]
fldbitoffset[RW]
fldlist[RW]
fldoffset[RW]
members[RW]
name[RW]

Public Instance Methods

==(o) click to toggle source

there is only one instance of a given named struct per parser so we just compare struct names here for comparison between parsers, see compare_deep

# File metasm/parse_c.rb, line 233
def ==(o)
        o.object_id == self.object_id or
        (o.class == self.class and o.name == self.name and ((o.name and true) or compare_deep(o)))
end
align(parser) click to toggle source
# File metasm/parse_c.rb, line 228
def align(parser) @members.to_a.map { |m| m.type.align(parser) }.max end
bitoffsetof(parser, name) click to toggle source
# File metasm/parse_c.rb, line 297
def bitoffsetof(parser, name)
        raise parser, 'undefined structure' if not members
        update_member_cache(parser) if not fldlist
        return if @fldlist[name] or @members.include?(name)
        raise parser, 'undefined union' if not @members
        raise parser, 'unknown union member' if not findmember(name)

        @members.find { |m|
                m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
        }.type.untypedef.bitoffsetof(parser, name)
end
compare_deep(o, seen = []) click to toggle source

compare to another structure, comparing members recursively (names and type) returns true if the self is same as o

# File metasm/parse_c.rb, line 240
def compare_deep(o, seen = [])
        return true if o.object_id == self.object_id
        return if o.class != self.class or o.name != self.name or o.attributes != self.attributes
        o.members.to_a.zip(self.members.to_a).each { |om, sm|
                return if om.name != sm.name
                return if om.type != sm.type
                if om.type.pointer?
                        ot = om.type
                        st = sm.type
                        500.times {        # limit for selfpointers (shouldnt happen)
                                break if not ot.pointer?
                                ot = ot.pointed.untypedef
                                st = st.pointed.untypedef
                        }
                        if ot.kind_of?(C::Union) and ot.name and not seen.include?(ot)
                                return if not st.compare_deep(ot, seen+[ot])
                        end
                end
        }
        true
end
dump(scope, r=[CRenderString.new], dep=[]) click to toggle source
# File metasm/parse_c.rb, line 3679
def dump(scope, r=[CRenderString.new], dep=[])
        if name
                r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
                r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1] << ' ' << @name
                dep |= [scope.struct_ancestors[@name]]
                [r, dep]
        else
                dump_def(scope, r, dep)
        end
end
dump_def(scope, r=[CRenderString.new], dep=[]) click to toggle source
# File metasm/parse_c.rb, line 3690
def dump_def(scope, r=[CRenderString.new], dep=[])
        r << CRenderString.new
        r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
        r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1]
        r.last << ' ' << @name if name
        if members
                r.last << ' {'
                @members.each_with_index { |m,i|
                        tr, dep = m.dump_def(scope, [CRenderString.new], dep)
                        tr.last << ':' << @bits[i].to_s if bits and @bits[i]
                        tr.last << ';'
                        r.concat tr.map { |s| CRenderString.new << "\t" << s }
                }
                r << CRenderString.new('}')
        end
        r.last << dump_attributes
        [r, dep]
end
dump_initializer(init, scope, r=[CRenderString.new], dep=[]) click to toggle source
Calls superclass method Metasm::C::Type#dump_initializer
# File metasm/parse_c.rb, line 3709
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
        return super(init, scope, r, dep) if not init.kind_of? ::Array
        r.last << '{ '
        showname = false
        @members.zip(init) { |m, i|
                if not i
                        showname = true
                        next
                end
                r.last << ', ' if r.last[-2, 2] != '{ '
                rt = [CRenderString.new]
                if showname
                        showname = false
                        rt << ".#{m.name} = "
                end
                rt, dep = m.type.dump_initializer(i, scope, rt, dep)
                r.last << rt.shift
                r.concat rt.map { |s| CRenderString.new << "\t" << s }
        }
        r.last << ' }'
        [r, dep]
end
expand_member_offset(c_parser, off, str) click to toggle source

resolve structptr + offset into 'str.membername' handles 'var.substruct1.array.foo' updates str returns the final member type itself works for Struct/Union/Array

# File metasm/parse_c.rb, line 410
def expand_member_offset(c_parser, off, str)
        # XXX choose in members, check sizeof / prefer structs
        m = @members.first
        str << '.' << m.name if m.name
        if m.type.respond_to?(:expand_member_offset)
                m.type.expand_member_offset(c_parser, off, str)
        else
                m.type
        end
end
findmember(name, igncase=false) click to toggle source
# File metasm/parse_c.rb, line 262
def findmember(name, igncase=false)
        raise 'undefined structure' if not members
        return @fldlist[name] if fldlist and @fldlist[name]

        name = name.downcase if igncase
        if m = @members.find { |m_| (n = m_.name) and (igncase ? n.downcase : n) == name }
                return m
        else
                @members.each { |m_|
                        if t = m_.type.untypedef and t.kind_of? Union and mm = t.findmember(name, igncase)
                                return mm
                        end
                }
        end

        nil
end
offsetof(parser, name) click to toggle source
# File metasm/parse_c.rb, line 280
def offsetof(parser, name)
        raise parser, 'undefined structure' if not members
        update_member_cache(parser) if not fldlist
        return 0 if @fldlist[name]

        if name.kind_of?(Variable)
                return 0 if @members.include? name
                raise ParseError, 'unknown union member'
        end

        raise parser, 'unknown union member' if not findmember(name)

        @members.find { |m|
                m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
        }.type.untypedef.offsetof(parser, name)
end
parse_initializer(parser, scope) click to toggle source
Calls superclass method Metasm::C::Type#parse_initializer
# File metasm/parse_c.rb, line 358
def parse_initializer(parser, scope)
        if tok = parser.skipspaces and tok.type == :punct and tok.raw == '{'
                # struct x toto = { 1, .4, .member[0][6].bla = 12 };
                raise tok, 'undefined struct' if not @members
                ret = []
                if tok = parser.skipspaces and (tok.type != :punct or tok.raw != '}')
                        parser.unreadtok tok
                        idx = 0
                        loop do
                                idx = parse_initializer_designator(parser, scope, ret, idx, true)
                                raise tok || parser, '"," or "}" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != '}' and tok.raw != ',')
                                break if tok.raw == '}'
                                raise tok, 'struct is smaller than that' if idx >= @members.length
                        end
                end
                ret
        else
                parser.unreadtok tok
                super(parser, scope)
        end
end
parse_initializer_designator(parser, scope, value, idx, root=true) click to toggle source

parses a designator+initializer eg '.toto = 4' or '.tutu[12].bla = 16' or (root ? '4' : '=4')

# File metasm/parse_c.rb, line 381
def parse_initializer_designator(parser, scope, value, idx, root=true)
        if nt = parser.skipspaces and nt.type == :punct and nt.raw == '.' and
                        nnt = parser.skipspaces and nnt.type == :string and
                        findmember(nnt.raw)
                raise nnt, 'unhandled indirect initializer' if not nidx = @members.index(@members.find { |m| m.name == nnt.raw })   # TODO
                if not root
                        value[idx] ||= []  # AryRecorder may change [] to AryRec.new, can't do v = v[i] ||= []
                        value = value[idx]
                end
                idx = nidx
                @members[idx].type.untypedef.parse_initializer_designator(parser, scope, value, idx, false)
        else
                parser.unreadtok nnt
                if root
                        parser.unreadtok nt
                        value[idx] = @members[idx].type.parse_initializer(parser, scope)
                else
                        raise nt || parser, '"=" expected' if not nt or nt.type != :punct or nt.raw != '='
                        value[idx] = parse_initializer(parser, scope)
                end
        end
        idx + 1
end
parse_members(parser, scope) click to toggle source
# File metasm/parse_c.rb, line 309
def parse_members(parser, scope)
        @fldlist = nil if fldlist    # invalidate fld offset cache
        @members = []
        # parse struct/union members in definition
        loop do
                raise parser if not tok = parser.skipspaces
                break if tok.type == :punct and tok.raw == '}'
                parser.unreadtok tok

                raise tok, 'invalid struct member type' if not basetype = Variable.parse_type(parser, scope)
                loop do
                        member = basetype.dup
                        member.parse_declarator(parser, scope)
                        member.type.length ||= 0 if member.type.kind_of?(Array)    # struct { char blarg[]; };
                        raise member.backtrace, 'member redefinition' if member.name and @members.find { |m| m.name == member.name }
                        @members << member

                        raise tok || parser if not tok = parser.skipspaces or tok.type != :punct

                        if tok.raw == ':'  # bits
                                raise tok, 'bad type for bitslice' if not member.type.integral?
                                bits = nil
                                raise tok, "bad bit count #{bits.inspect}" if not bits = CExpression.parse(parser, scope, false) or
                                        not bits.constant? or !(bits = bits.reduce(parser)).kind_of? ::Integer
                                #raise tok, 'need more bits' if bits > 8*parser.sizeof(member)
                                # WORD wReserved:17; => yay windows.h
                                (@bits ||= [])[@members.length-1] = bits
                                raise tok || parser, '"," or ";" expected' if not tok = parser.skipspaces or tok.type != :punct
                        end

                        case tok.raw
                        when ';'; break
                        when ','
                        when '}'; parser.unreadtok(tok); break
                        else raise tok, '"," or ";" expected'
                        end
                end
        end
        parse_attributes(parser)
end
update_member_cache(parser) click to toggle source

updates the @fldoffset / @fldbitoffset hash storing the offset of members

# File metasm/parse_c.rb, line 351
def update_member_cache(parser)
        @fldlist = {}
        @members.to_a.each { |m|
                @fldlist[m.name] = m if m.name
        }
end