Python idaapi.tinfo_t() Examples

The following are 24 code examples of idaapi.tinfo_t(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module idaapi , or try the search function .
Example #1
Source File: apply_callee_type.py    From flare-ida with Apache License 2.0 6 votes vote down vote up
def getBuiltinGlobalTypePython(self):
        logger.debug('Getting GlobalType the Python way')
        sym = idaapi.til_symbol_t()
        if using_ida7api:
            ret = idaapi.choose_named_type(sym, idaapi.get_idati(), 'Choose type to apply', idaapi.NTF_SYMM, None)
        else:
            ret = idaapi.choose_named_type2(idaapi.cvar.idati, 'Choose type to apply', idaapi.NTF_SYMM, None, sym)
        if not ret:
            logger.debug('User canceled. Bailing out')
            return

        tuple = idaapi.get_named_type(sym.til, sym.name, 0)

        if tuple == None:
            logger.debug('Could not find %s', sym.name)
            return

        tinfo = idaapi.tinfo_t()
        tinfo.deserialize(sym.til, tuple[1], tuple[2])

        return tinfo 
Example #2
Source File: IDATypeWrapers.py    From DIE with MIT License 6 votes vote down vote up
def get_array_data(self):
        """
        Extract the array data from tinfo_t object and populate all relevant class properties.
        @return: True if successful, otherwise False
        """

        try:
            if self.type_info.is_array():
                if self.type_info.get_array_details(self.array_type_data):
                    self.element_type = self.array_type_data.elem_type
                    self.element_num = self.array_type_data.nelems
                    self.element_size = self.element_type.get_size()
                    return True

            return False

        except Exception as ex:
            self.logger.exception("Array: Error while getting array data: %s", ex)
            return False

#######################################################################################################################
#
#  IDA Function Argument class wrapper
# 
Example #3
Source File: IDATypeWrapers.py    From DIE with MIT License 6 votes vote down vote up
def __init__(self, ea, iatEA=None, library_name=None):
        """
        Ctor
        """
        self.logger = logging.getLogger(__name__)

        self.ea = ea        # Effective Address of the function
        self.iatEA = iatEA  # If imported function, the address in the IAT

        try:
            function = sark.Function(ea)
        except sark.exceptions.SarkNoFunction:
            raise DIE.Lib.DIE_Exceptions.DieNoFunction("No Function at 0x%08X" % (ea, ))

        self.funcName = get_function_name(function.ea)
        self.func_start = function.startEA
        self.func_end = function.endEA

        self.proto_ea = self.getFuncProtoAdr()      # Address of function prototype
        self.typeInfo = idaapi.tinfo_t()            # Function type info
        self.funcInfo = idaapi.func_type_data_t()   # Function info
        self.argNum = 0                             # Number of input arguments

        self.args = []      # Function argument list
        self.retArg = None  # Return argument

        self.library_name = library_name  # If library function, name of containing library
        self.isLibFunc = False
        if self.iatEA:
            self.isLibFunc = True  # Is this a library function

        elif sark.Function(ea).flags & (idaapi.FUNC_LIB | idaapi.FUNC_THUNK):
            self.isLibFunc = True

        try:
            self.getArguments()

        except Exception as ex:
            self.logger.error("Failed to get function arguments for function %s: %s", self.funcName, ex) 
Example #4
Source File: IDATypeWrapers.py    From DIE with MIT License 6 votes vote down vote up
def getStructData(self):
        """
        Extract the struct data from tinfo_t object and populate all relevant class properties.
        @return: True if successful, otherwise False
        """

        if self.type_info.is_udt():
            if self.type_info.get_udt_details(self.udt_type_data):

                self.name = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, self.type_info, '', '')
                self.size = self.udt_type_data.size
                self.element_num = len(self.udt_type_data)
                self.is_union = self.udt_type_data.is_union

                return True

        return False 
Example #5
Source File: _declaration.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
def parse(info):
    '''Parse the string `info` into an ``idaapi.tinfo_t``.'''
    til, ti = idaapi.get_idati(), idaapi.tinfo_t(),

    # Convert info to a string if it's a tinfo_t
    info_s = "{!s}".format(info) if isinstance(info, idaapi.tinfo_t) else info

    # Firstly we need to ';'-terminate the type the user provided in order
    # for IDA's parser to understand it.
    terminated = info_s if info_s.endswith(';') else "{:s};".format(info_s)

    # Ask IDA to parse this into a tinfo_t for us. We pass the silent flag so
    # that we're responsible for raising an exception if there's a parsing
    # error of some sort. If it succeeds, then we can return our typeinfo.
    # Otherwise we return None because of the inability to parse it.
    return None if idaapi.parse_decl(ti, til, terminated, idaapi.PT_SIL) is None else ti 
Example #6
Source File: struct_typer.py    From flare-ida with Apache License 2.0 6 votes vote down vote up
def processStructIDA7(self, regPrefix, struc, sid):
        members = loadMembers(struc, sid)
        foundFunctions = 0
        for off, name, memb in members:
            funcname  = self.filterName(regPrefix, name)
            tup = idaapi.get_named_type(None, funcname, idaapi.NTF_SYMM)
            if tup is None:
                continue
            code, type_str, fields_str, cmt, field_cmts, sclass, value  = tup
            foundFunctions += 1
            tif = idaapi.tinfo_t()
            tif.deserialize(None, type_str, fields_str, cmt)
            if not tif.is_func():
                logger.debug('Found named type, but not a function: %s', funcname)
                continue
            tif.create_ptr(tif)
            ret = idaapi.set_member_tinfo(struc, memb, off, tif, 0)
            if ret != idaapi.SMT_OK:
                logger.info("Got set_member_tinfo ret code: %d" % ret)
            else:
                logger.info('set_member_tinfo: %s', tif.dstr()) 
Example #7
Source File: ready_patterns.py    From HRAST with MIT License 6 votes vote down vote up
def test_xx(idx, ctx):
    import ida_typeinf
    uni = ctx.get_expr('union_type')
    var = ctx.get_var('v1')
    tname =  var.typ.dstr().split(' ')[0]
    tinfo = idaapi.tinfo_t()
    if tname == 'class1':
        idaapi.parse_decl2(idaapi.cvar.idati, 'vptr1_1 *;', tinfo, idaapi.PT_TYP)
        uni[0].type = tinfo
        uni[0].m = 0
    elif tname == "class2":
        idaapi.parse_decl2(idaapi.cvar.idati, 'struc_5 *;', tinfo, idaapi.PT_TYP)
        uni[0].type = tinfo
        uni[0].m = 1
    else:
        return False
    return True 
Example #8
Source File: __init__.py    From idawilli with Apache License 2.0 6 votes vote down vote up
def get_winapi_decl(name):
    '''
    fetch the C function declaration for the given Windows API function.
    '''
    tup = idaapi.get_named_type(None, name, idaapi.NTF_SYMM)
    if tup is None:
        raise ValueError("failed to fetch type")
    code, type_str, fields_str, cmt, field_cmts, sclass, value = tup
    ti = idaapi.tinfo_t()
    ti.deserialize(None, type_str, fields_str, cmt)

    # the rendered declaration from IDA doesn't include the function name,
    # so insert the function name, naively.
    #
    # for example;
    #
    #    > DWORD (DWORD a, DWORD b)
    #    < DWORD foo(DWORD a, DWORD b);
    decl = str(ti).replace("(", " " + name + "(") + ";"

    return decl 
Example #9
Source File: structure.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
def typeinfo(self, info):
        '''Sets the typeinfo of the structure to `info`.'''
        try:
            ti = database.type(self.id, info)

        # If we caught a TypeError, then we received a parsing error that
        # we should re-raise for the user.
        except E.InvalidTypeOrValueError:
            cls = self.__class__
            raise E.InvalidTypeOrValueError(u"{:s}({:#x}).typeinfo : Unable to parse the specified type declaration ({!s}).".format('.'.join((__name__, cls.__name__)), self.id, utils.string.repr(info)))

        # If we caught an exception trying to get the typeinfo for the
        # structure, then port it to our class and re-raise.
        except E.DisassemblerError:
            cls = self.__class__
            raise E.DisassemblerError(u"{:s}({:#x}).typeinfo : Unable to apply `idaapi.tinfo_t()` to structure {:s}.".format('.'.join((__name__, cls.__name__)), self.id, self.name))
        return 
Example #10
Source File: structure.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def typeinfo(self):
        '''Return the type info of the member.'''
        try:
            ti = database.type(self.id)

        # If we caught an exception trying to get the typeinfo for the
        # structure, then port it to our class.
        except E.DisassemblerError:
            cls = self.__class__
            raise E.DisassemblerError(u"{:s}({:#x}).typeinfo : Unable to determine `idaapi.tinfo_t()` for structure {:s}.".format('.'.join((__name__, cls.__name__)), self.id, self.name))

        # Return the structure type that we guessed back to the caller.
        return ti 
Example #11
Source File: apply_callee_type.py    From flare-ida with Apache License 2.0 5 votes vote down vote up
def getBuiltinGlobalType(self):

        # Ensure proper IDA Python methods are exposed
        if hasattr(idaapi, "get_named_type") and hasattr(idaapi.tinfo_t, "deserialize"):
            return self.getBuiltinGlobalTypePython()

        # Fall back to calling exports directly with Ctypes
        else:
            return self.getBuiltinGlobalTypeCtypes() 
Example #12
Source File: apply_callee_type.py    From flare-ida with Apache License 2.0 5 votes vote down vote up
def getLocalType(self):
        ret = idaapi.choose_local_tinfo(idaapi.cvar.idati, 'Choose local type to apply', None, None)
        if not ret:
            logger.debug('User canceled. Bailing out')
            return
        #ret is a numbered type rather than the name
        tinfo = idaapi.tinfo_t()
        tinfo.get_numbered_type(idaapi.cvar.idati, ret)
        return tinfo 
Example #13
Source File: apply_callee_type.py    From flare-ida with Apache License 2.0 5 votes vote down vote up
def getUserDeclType(self, decl):
        tinfo = idaapi.tinfo_t()
        #logger.debug('Trying to parse declaration: %r', decl)
        ret = idaapi.parse_decl2(idaapi.cvar.idati, decl, tinfo, idaapi.PT_TYP)
        #logger.debug('Return from parse_decl2: %r', ret)
        if ret is None:
            logger.info('parse_decl2 failed')
            return None
        return tinfo 
Example #14
Source File: IdaTools.py    From apiscout with BSD 2-Clause "Simplified" License 5 votes vote down vote up
def helper_getTinfoOfFuncName(self, funcName):
        try:
            sym = til_symbol_t()
            sym.til = cvar.idati
            sym.name = funcName
            tinfo = idaapi.tinfo_t()
            namedType = get_named_type(sym.til, sym.name, 0)
            if namedType == None:
                return tinfo, False
            tinfo.deserialize(sym.til, namedType[1], namedType[2])
            return tinfo, True
        except:
            return None, False 
Example #15
Source File: ui.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def format_item(self, num_printer, storage, item):
        if item is None or isinstance(item, bool):
            storage.append("{!s}".format(item))
        elif isinstance(item, six.string_types):
            storage.append(self.format_basestring(item))
        elif isinstance(item, six.integer_types):
            storage.append(num_printer(item))
        elif isinstance(item, idaapi.tinfo_t):
            storage.append("{!s}".format(item))
        elif item.__class__ is list:
            self.format_seq(num_printer, storage, item, '[', ']')
        elif item.__class__ is tuple:
            self.format_seq(num_printer, storage, item, '(', ')')
        elif item.__class__ is set:
            self.format_seq(num_printer, storage, item, 'set([', '])')
        elif item.__class__ is dict:
            storage.append('{')
            for idx, pair in enumerate(item.items()):
                if idx > 0:
                    storage.append(', ')
                self.format_item(num_printer, storage, pair[0])
                storage.append(": ")
                self.format_item(num_printer, storage, pair[1])
            storage.append('}')
        else:
            storage.append("{!r}".format(item)) 
Example #16
Source File: structure.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def typeinfo(self):
        '''Return the type info of the member.'''
        ti = idaapi.tinfo_t()
        ok = idaapi.get_or_guess_member_tinfo2(self.ptr, ti) if idaapi.__version__ < 7.0 else idaapi.get_or_guess_member_tinfo(ti, self.ptr)
        if not ok:
            cls = self.__class__
            logging.fatal(u"{:s}({:#x}).typeinfo : Unable to determine `idaapi.tinfo_t()` for member {:s}.".format('.'.join((__name__, cls.__name__)), self.id, self.name))
        return ti 
Example #17
Source File: function.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def __new__(cls, func, info):
        '''Apply the ``idaapi.tinfo_t`` typeinfo in `info` to the function `func`.'''
        _, ea = interface.addressOfRuntimeOrStatic(func)

        # In order to apply the typeinfo with idaapi.apply_cdecl, we need the
        # typeinfo as a string. To accomplish this, we need need the typeinfo
        # with its name attached.
        fname = database.name(ea)
        realname = internal.declaration.unmangle_name(fname)

        # Filter out invalid characters from the function name since we're going
        # to use this to render the declaration next.
        valid = {item for item in string.digits}
        valid |= {item for item in ':'}
        filtered = str().join(item if item in valid or idaapi.is_valid_typename(utils.string.to(item)) else '_' for item in realname)

        # Now we have the name and its filtered, we can simply render it.
        try:
            tinfo_s = idaapi.print_tinfo('', 0, 0, 0, info, utils.string.to(filtered), '')

        # If we caught an error, then we couldn't render the string for some reason.
        except Exception:
            raise E.DisassemblerError(u"{:s}({:#x}, \"{:s}\") : Unable to render `idaapi.tinfo_t()` with name (\"{!s}\") to a string.".format('.'.join((__name__, cls.__name__)), ea, utils.string.escape("{!s}".format(info), '"'), utils.string.escape(realname, '"')))

        # Recurse back into ourselves in order to call idaapi.apply_cdecl
        return cls(ea, tinfo_s) 
Example #18
Source File: function.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def __new__(cls, func):
        '''Return the typeinfo for the function `func` as a ``idaapi.tinfo_t``.'''
        rt, ea = interface.addressOfRuntimeOrStatic(func)
        try:
            ti = database.type(ea)

        # If we caught an exception trying to get the typeinfo for the
        # function, then port it to our class.
        except E.DisassemblerError:
            raise E.DisassemblerError(u"{:s}.info({:#x}) : Unable to determine `idaapi.tinfo_t()` for function.".format('.'.join((__name__, cls.__name__)), ea))

        # Return it to the caller
        return ti 
Example #19
Source File: function.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def __new__(cls):
        '''Return the typeinfo for the current function as a ``idaapi.tinfo_t``.'''
        return cls(ui.current.address()) 
Example #20
Source File: fn_fuzzy.py    From ida_haru with Apache License 2.0 5 votes vote down vote up
def export(self):
        if self.existed() and not self.f_update:
            info('{}: The sample records are present in DB. skipped.'.format(self.sha256))
            return False

        self.cur.execute("REPLACE INTO sample values(?, ?)", (self.sha256, self.idb_path))

        pnum = tnum = 0
        records = []
        for fva in idautils.Functions():
            fname = get_func_name(fva)
            tnum += 1
            if self.exclude_libthunk(fva, fname):
                continue
            fhd, bsize = self.calc_fn_ssdeep(fva, fname)
            fhm, cfgnum = self.calc_fn_machoc(fva, fname)
            if fhd and fhm:
                pnum += 1
                f_ana = bool(self.ana_pat.search(fname)) if self.f_ana_exp else False
                tinfo = idaapi.tinfo_t()
                idaapi.get_tinfo(fva, tinfo)
                ptype = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, tinfo, fname, '')
                ptype = ptype + ';' if ptype is not None else ptype
                # fva is 64-bit int causing OverflowError
                records.append((self.sha256, '{:#x}'.format(fva), fname, fhd, fhm, f_ana, bsize, ptype)) 
                self.debug('EXPORT {} at {:#x}: ssdeep={} (size={}), machoc={} (num of CFG={})'.format(fname, fva, fhd, bsize, fhm, cfgnum))

        self.cur.executemany("REPLACE INTO function values (?, ?, ?, ?, ?, ?, ?, ?)", records)
        success ('{} of {} functions exported'.format(pnum, tnum))
        return True 
Example #21
Source File: fn_fuzzy.py    From ida_haru with Apache License 2.0 5 votes vote down vote up
def activate(self, ctx):
        sel = []
        for idx in ctx.chooser_selection:
            # rename the function
            ea = get_name_ea_simple(self.items[idx][2])
            sfname = str(self.items[idx][4])
            #set_name(ea, sfname)
            idaapi.do_name_anyway(ea, sfname)
            success('{:#x}: renamed to {}'.format(ea, sfname))
            # set the function prototype
            sptype = str(self.items[idx][5])
            if sptype != 'None':
                tinfo = idaapi.tinfo_t()
                idaapi.parse_decl2(idaapi.cvar.idati, sptype, tinfo, 0)
                #idaapi.apply_callee_tinfo(ea, tinfo)
                if idaapi.apply_tinfo(ea, tinfo, 0):
                    success('{:#x}: function prototype set to {}'.format(ea, sptype))
                else:
                    error('{:#x}: function prototype set FAILED (maybe you should import the types?)'.format(ea))
                    if ask_yn(0, 'Do you import types from the secondary idb?') == 1:
                        if self.import_types():
                            tinfo = idaapi.tinfo_t()
                            idaapi.parse_decl2(idaapi.cvar.idati, sptype, tinfo, 0)
                            if idaapi.apply_tinfo(ea, tinfo, 0):
                                success('{:#x}: function prototype set to {}'.format(ea, sptype))
                            else:
                                error('{:#x}: function prototype set FAILED again'.format(ea))
                        
            # insert the comment
            score = self.items[idx][0]
            mmatch = self.items[idx][1]
            cmt = 'fn_fuzzy: ssdeep={}, machoc={}'.format(score, mmatch)
            set_func_cmt(ea, cmt, 1)
            #set_decomplier_cmt(ea, cmt) # not sure how to avoid orphan comment

        # update the Choose rows
        ida_kernwin.refresh_chooser(self.title) 
Example #22
Source File: structure.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
def typeinfo(self, info):
        '''Set the type info of the member to `info`.'''
        til, ti = idaapi.get_idati(), idaapi.tinfo_t(),

        # Convert info to a string if it's a tinfo_t
        info_s = "{!s}".format(info) if isinstance(info, idaapi.tinfo_t) else info

        # Firstly we need to ';'-terminate the type the user provided in order
        # for IDA's parser to understand it.
        terminated = info_s if info_s.endswith(';') else "{:s};".format(info_s)

        # Now that we've prepped everything, ask IDA to parse this into a
        # tinfo_t for us. We pass the silent flag so that we can raise an
        # exception if there's a parsing error of some sort.
        res = idaapi.parse_decl(ti, til, terminated, idaapi.PT_SIL)
        if res is None:
            cls = self.__class__
            raise E.InvalidTypeOrValueError(u"{:s}({:#x}).typeinfo : Unable to parse the specified type declaration ({!s}).".format('.'.join((__name__, cls.__name__)), self.id, utils.string.repr(info)))

        # Now we can pass our tinfo_t along with the member information to IDA.
        res = idaapi.set_member_tinfo(self.parent.ptr, self.ptr, self.ptr.get_soff(), ti, 0)
        if res == idaapi.SMT_OK:
            return

        # We failed, so just raise an exception for the user to handle.
        elif res == idaapi.SMT_FAILED:
            cls = self.__class__
            raise E.DisassemblerError(u"{:s}({:#x}).typeinfo : Unable to assign typeinfo ({!s}) to structure member {:s}.".format('.'.join((__name__, cls.__name__)), self.id, utils.string.repr(info), utils.string.repr(self.name)))

        # If we received an alternative return code, then build a relevant
        # message that we can raise with our exception.
        if res == idaapi.SMT_BADARG:
            message = 'invalid parameters'
        elif res == idaapi.SMT_NOCOMPAT:
            message = 'incompatible type'
        elif res == idaapi.SMT_WORSE:
            message = 'worse type'
        elif res == idaapi.SMT_SIZE:
            message = 'invalid type for member size'
        elif res == idaapi.SMT_ARRAY:
            message = 'setting function argument as an array is illegal'
        elif res == idaapi.SMT_OVERLAP:
            message = 'the specified type would result in member overlap'
        elif res == idaapi.SMT_KEEP:
            message = 'the specified type is not ideal'
        else:
            message = "unknown error {:#x}".format(res)

        # Finally we can raise our exception so that the user knows whats up.
        cls = self.__class__
        raise E.DisassemblerError(u"{:s}({:#x}).typeinfo : Unable to assign typeinfo ({!s}) to structure member {:s} ({:s}).".format('.'.join((__name__, cls.__name__)), self.id, utils.string.repr(info), utils.string.repr(self.name), message)) 
Example #23
Source File: function.py    From ida-minsc with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
def __new__(cls, func, info):
        '''Parse the typeinfo string in `info` to an ``idaapi.tinfo_t`` and apply it to the function `func`.'''
        til = idaapi.get_idati()
        _, ea = interface.addressOfRuntimeOrStatic(func)
        conventions = {'__cdecl', '__stdcall', '__fastcall', '__thiscall', '__pascal', '__usercall', '__userpurge'}

        # First extract the arguments that we were given, and use that to extract
        # the name of the function (and possibly the usercall register)
        parameters = internal.declaration.extract.arguments(info)
        noparameters = info[:-len(parameters)]

        # Figure out which part of `noparameters` contains the actual name
        if any(item in noparameters for item in conventions):
            components = noparameters.split(' ')
            index = next(index for index, item in enumerate(components) if any(item.endswith(cc) for cc in conventions))
            funcname = ' '.join(components[-index:])

        # If nothing was found, then we have no choice but to chunk it out
        # according to the first space.
        else:
            funcname = noparameters.rsplit(' ', 1)[-1]

        # Filter out invalid characters from the name so that we can apply this
        # as a declaration.
        valid = {item for item in string.digits}
        if '__usercall' in noparameters:
            valid |= {item for item in '<>@'}
        valid |= {item for item in ':'}
        funcname_s = str().join(item if item in valid or idaapi.is_valid_typename(utils.string.to(item)) else '_' for item in funcname)

        # Filter out invalid characters from the parameters so that this can
        # be applied as a declaration
        valid |= {item for item in ', *&[]'}
        parameters_s = str().join(item if item in valid or idaapi.is_valid_typename(utils.string.to(item)) else '_' for item in parameters.lstrip('(').rstrip(')'))

        # Now we can replace both the name and parameters in our typeinfo string
        # with the filtered versions.
        info_s = "{!s} {:s}({:s})".format(noparameters[:-len(funcname)].strip(), funcname_s, parameters_s)

        # Terminate the typeinfo string with a ';' so that IDA can parse it.
        terminated = info_s if info_s.endswith(';') else "{:s};".format(info_s)

        # Now we should just be able to apply it to the function.
        ok = idaapi.apply_cdecl(idaapi.get_idati(), ea, terminated)
        if not ok:
            raise E.InvalidTypeOrValueError(u"{:s}.info({:#x}) : Unable to apply the specified type declaration (\"{!s}\").".format('.'.join((__name__, cls.__name__)), ea, utils.string.escape(info, '"')))

        # Just return the type we applied to the user.
        return cls(ea) 
Example #24
Source File: LazyIDA.py    From LazyIDA with MIT License 4 votes vote down vote up
def remove_rettype(self, vu):
        if vu.item.citype == idaapi.VDI_FUNC:
            # current function
            ea = vu.cfunc.entry_ea
            old_func_type = idaapi.tinfo_t()
            if not vu.cfunc.get_func_type(old_func_type):
                return False
        elif vu.item.citype == idaapi.VDI_EXPR and vu.item.e.is_expr() and vu.item.e.type.is_funcptr():
            # call xxx
            ea = vu.item.get_ea()
            old_func_type = idaapi.tinfo_t()

            func = idaapi.get_func(ea)
            if func:
                try:
                    cfunc = idaapi.decompile(func)
                except idaapi.DecompilationFailure:
                    return False

                if not cfunc.get_func_type(old_func_type):
                    return False
            else:
                return False
        else:
            return False

        fi = idaapi.func_type_data_t()
        if ea != idaapi.BADADDR and old_func_type.get_func_details(fi):
            # Return type is already void
            if fi.rettype.is_decl_void():
                # Restore ret type
                if ea not in self.ret_type:
                    return True
                ret = self.ret_type[ea]
            else:
                # Save ret type and change it to void
                self.ret_type[ea] = fi.rettype
                ret = idaapi.BT_VOID

            # Create new function info with new rettype
            fi.rettype = idaapi.tinfo_t(ret)

            # Create new function type with function info
            new_func_type = idaapi.tinfo_t()
            new_func_type.create_func(fi)

            # Apply new function type
            if idaapi.apply_tinfo(ea, new_func_type, idaapi.TINFO_DEFINITE):
                return vu.refresh_view(True)

        return False