Exemple #1
0
def anon_ref(type_def):
    '''Return reference to anonymous struct or enum'''
    return lambda name: c_ast.TypeDecl(name, [], type_def)
Exemple #2
0
def base_type_ref(basetypename):
    basetypename = basetypename.split(' ')
    return lambda x: c_ast.TypeDecl(x, [], c_ast.IdentifierType(basetypename))
Exemple #3
0
def to_c_process(die, by_offset, names, rv, written, preref=False):
    if DEBUG:
        print("to_c_process", die.offset, preref)

    def get_type_ref(die, attr):
        '''
        Get type ref for a type attribute.
        A type ref is a function that, given a name, constructs a syntax tree
        for referring to that type.
        '''
        type_ = get_ref(die, 'type')
        if DEBUG:
            print(die.offset, "->", type_)
        if type_ is None:
            ref = base_type_ref('void')
        else:
            ref = names.get(type_)
            if ref is None:
                #ref = base_type_ref('unknown_%i' % type_)
                ref = to_c_process(by_offset[type_],
                                   by_offset,
                                   names,
                                   rv,
                                   written,
                                   preref=True)
            elif ref is ERROR:
                raise ValueError("Unexpected recursion")
        return ref

    names[die.offset] = typeref = ERROR(
        die.offset)  # prevent unbounded recursion

    # Typeref based on name: simple
    name = get_str(die, 'name')
    if name is not None:
        try:
            prefix = TAG_NODE_CONS[die.tag](name, None)
        except KeyError:
            pass
        else:  # store early, to allow self-reference
            names[die.offset] = typeref = lambda name: c_ast.TypeDecl(
                name, [], prefix)
            if preref:  # early-out
                return typeref

    if die.tag == DW_TAG.enumeration_type:
        items = []
        for enumval in die.children:
            assert (enumval.tag == DW_TAG.enumerator)
            (sname, const_value) = (not_none(get_str(enumval, 'name')),
                                    not_none(get_int(enumval, 'const_value')))
            items.append(EnumItem(sname, const_value))
        enum = c_ast.Enum(name, c_ast.EnumeratorList(items))
        if name is None:
            typeref = anon_ref(enum)
        else:
            if written[(die.tag, name)] != WRITTEN_FINAL:
                rv.append(SimpleDecl(enum))
                written[(die.tag,
                         name)] = WRITTEN_FINAL  # typedef is always final

    elif die.tag == DW_TAG.typedef:
        assert (name is not None)
        ref = get_type_ref(die, 'type')
        if written[(die.tag, name)] != WRITTEN_FINAL:
            rv.append(c_ast.Typedef(name, [], ['typedef'], ref(name)))
            written[(die.tag, name)] = WRITTEN_FINAL  # typedef is always final
        typeref = base_type_ref(name)

    elif die.tag == DW_TAG.base_type:  # IdentifierType
        if name is None:
            name = 'unknown_base'  #??
        if written[(die.tag, name)] != WRITTEN_FINAL:
            rv.append(Comment("Basetype: %s" % name))
            written[(die.tag, name)] = WRITTEN_FINAL  # typedef is always final
        typeref = base_type_ref(name)

    elif die.tag == DW_TAG.pointer_type:
        ref = get_type_ref(die, 'type')
        typeref = ptr_to_ref(ref)

    elif die.tag in [
            DW_TAG.const_type, DW_TAG.volatile_type, DW_TAG.restrict_type
    ]:
        ref = get_type_ref(die, 'type')
        typeref = qualified_ref(ref, die.tag)

    elif die.tag in [DW_TAG.structure_type, DW_TAG.union_type]:
        if get_flag(die, 'declaration', False):
            items = None  # declaration only
            level = WRITTEN_PREREF
        else:
            items = []
            for enumval in die.children:
                if enumval.tag != DW_TAG.member:
                    warning(
                        'Unexpected tag %s inside struct or union (die %i)' %
                        (DW_TAG.fmt(enumval.tag), die.offset))
                    continue
                # data_member_location and bit_size / bit_offset as comment for fields
                bit_size = None
                comment = []
                if 'data_member_location' in enumval.attr_dict:
                    ml = enumval.attr_dict['data_member_location']
                    if ml.form in [
                            'sdata', 'data1', 'data2', 'data4', 'data8'
                    ]:
                        comment.append("+0x%x" % ml.value)
                    elif ml.form in ['block', 'block1']:
                        expr = ml.value
                        if len(expr.instructions) >= 1 and expr.instructions[
                                0].opcode == DW_OP.plus_uconst:
                            comment.append("+0x%x" %
                                           expr.instructions[0].operand_1)

                if 'bit_size' in enumval.attr_dict:
                    bit_size = get_int(enumval, 'bit_size')
                if 'bit_offset' in enumval.attr_dict:
                    bit_offset = get_int(enumval, 'bit_offset')
                    comment.append('bit %i..%i' %
                                   (bit_offset, bit_offset + bit_size - 1))
                if 'byte_size' in enumval.attr_dict:
                    comment.append('of %i' %
                                   (8 * get_int(enumval, 'byte_size')))
                # TODO: validate member location (alignment), bit offset
                if 'name' in enumval.attr_dict:
                    ename = expect_str(enumval.attr_dict['name'])
                else:
                    ename = None
                ref = get_type_ref(enumval, 'type')
                items.append(
                    c_ast.Decl(ename, [], [], [],
                               ref(ename),
                               None,
                               IntConst(bit_size),
                               postcomment=(' '.join(comment))))
            level = WRITTEN_FINAL

        cons = TAG_NODE_CONS[die.tag](name, items)
        if name is None:  # anonymous structure
            typeref = anon_ref(cons)
        else:
            if written[(die.tag, name)] < level:
                rv.append(SimpleDecl(cons))
                written[(die.tag, name)] = level

    elif die.tag == DW_TAG.array_type:
        subtype = get_type_ref(die, 'type')
        count = None
        for val in die.children:
            if val.tag == DW_TAG.subrange_type:
                count = get_int(val, 'upper_bound')
        if count is not None:
            count += 1  # count is upper_bound + 1
        typeref = array_ref(subtype, count)

    elif die.tag in [DW_TAG.subroutine_type, DW_TAG.subprogram]:
        inline = get_int(die, 'inline', 0)
        returntype = get_type_ref(die, 'type')
        args = []
        for i, val in enumerate(die.children):
            if val.tag == DW_TAG.formal_parameter:
                argtype = get_type_ref(val, 'type')
                argname = get_str(val, 'name', '')
                args.append(c_ast.Typename([], argtype(argname)))
        cons = lambda name: c_ast.FuncDecl(c_ast.ParamList(args),
                                           returntype(name))

        if die.tag == DW_TAG.subprogram:
            # Is it somehow specified whether this function is static or external?
            assert (name is not None)
            if written[(die.tag, name)] != WRITTEN_FINAL:
                if inline:  # Generate commented declaration for inlined function
                    #rv.append(Comment('\n'.join(cons.generate())))
                    rv.append(
                        Comment('inline %s' %
                                (CGenerator().visit(SimpleDecl(cons(name))))))
                else:
                    rv.append(SimpleDecl(cons(name)))
                written[(die.tag, name)] = WRITTEN_FINAL
        else:  # DW_TAG.subroutine_type
            typeref = cons
    else:
        # reference_type, class_type, set_type   etc
        # variable
        if name is None or written[(die.tag, name)] != WRITTEN_FINAL:
            rv.append(
                Comment("Unhandled: %s\n%s" %
                        (DW_TAG.fmt(die.tag), unistr(die))))
            written[(die.tag, name)] = WRITTEN_FINAL
        warning("unhandled %s (die %i)" % (DW_TAG.fmt(die.tag), die.offset))

    names[die.offset] = typeref
    return typeref