ida-minsc: An InvalidTypeOrValue exception is being raised when trying to fetch the type for a function being listed.

database.functions.list() throws exception, the user probably wanted to list all functions.

database.functions.list()
internal.interface.tinfo.function_details(0x401029, '') : The type that was received ('') for the specified function (0x401029) was not a function type.

Also database.functions.list(like=‘*’) throws Exception:

database.functions.list(like='*')
InvalidTypeOrValueError: internal.interface.tinfo.function_details(0x401029, '') : The type that was received ('') for the specified function (0x401029) was not a function type.

https://github.com/arizvisa/ida-minsc/blob/af07f167a0992aed3f3a2a1670593880baa57820/base/database.py#L595C11-L595C11

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Comments: 20 (10 by maintainers)

Most upvoted comments

I closed the PR, and will close this issue. If you feel that is in error, let me know and I’ll re-open.

Btw, you should consider the “persistence-refactor” branch if you believe the things in this plugin are actually useful to you. It’s development is still ongoing, but it significantly improves structure arithmetic, all the matchers allow iterable types, tagging and searches are improved, operand references can be used for referencing specific operands, all references now bundle their access (‘rwx’), etc. There’s quite a lot. The “master” branch is about a year behind, and is before i decided to go “all-in” on some of the original features.

As an example, since you’re looking at database.functions.list, you can do.

db.functions.list(ea=[addr1, addr2, addr3])

# now capture the results
addrs = db.functions(ea=[addr1, addr2, addr3])

# feed them back into the matchers
refs = [func.up(ea) for ea in addrs]
db.functions.list(ea=itertools.chain(*refs), like='CCmdTarget::*')

# consolidate into one line, and just list all functions that reference a function that references your target function
db.functions.list(ea=itertools.chain(*map(func.up, db.functions(ea=[addr1, addr2, addr2]))))

Or if you want to distinguish calls in the current function that dereference an address.

for ref in func.calls():
    if '&' in ref: print(db.disasm(ref))

# something with registers being written to
for ref in func.registers(ins.reg.eax):
    if 'w' in ref: print(db.disasm(ref))

If you have any questions, feel free to ask in the discussions.

Lol. And that, hands-down, is why Python is a terrible programming language.

I added

setattr(ida_typeinf.tinfo_t, '__bool__', lambda self: self.is_well_defined())

to my code and now it all works well.

I found the problem and it was in one of my scripts (that I didn’t knew was loaded). It was this line:

setattr(ida_typeinf.tinfo_t, '__len__', lambda self: self.get_size() if self.get_size() != ida_typeinf.BADSIZE else 0)

That is messing up the if-statment in

        # Then we'll return each type that we fetched while prioritizing the one that is
        # stored in NSUP_, then the guessed one, and then falling back to the missing one.
        if nsupped or guessed:
            return nsupped or guessed # nsupped is OK here but the __len__() returns 0 and that makes the    if nsupped evaluate to false.

tinfo_t with function prototypes have a size of 0 and when there is no bool it checks for len and if that returns 0 then the if statement fails.

Sorry to take up your time!

Now is the database.functions.list() also working as expected ❤️

I tried it and I got the following trace log:

Jupyter QtConsole 5.4.0
Python 3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.9.0 -- An enhanced Interactive Python. Type '?' for help.

database.functions.list()
---------------------------------------------------------------------------
DisassemblerError                         Traceback (most recent call last)
Cell In[1], line 1
----> 1 database.functions.list()

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\_utils.py:694, in database.list(*arguments, **keywords)
    691 # Now we have a matching callable for the user's parameters, and we just need
    692 # to unpack our individual parameters and dispatch to the callable with them.
    693 parameters, wild_parameters, keyword_parameters = result_parameters
--> 694 return result_callable(*itertools.chain(parameters, wild_parameters), **keyword_parameters)

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\database.py:598, in functions.list(cls, **type)
    596     '''List all of the functions in the database with a glob that matches `string`.'''
    597     return cls.list(like=string)
--> 598 @utils.multicase()
    599 @classmethod
    600 @utils.string.decorate_arguments('name', 'like', 'regex')
    601 def list(cls, **type):
    602     '''List all of the functions in the database that match the keyword specified by `type`.'''
    603     listable = []

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\_utils.py:1994, in transform.<locals>.wrapper(F, *rargs, **rkwds)
   1992         cls = E.__class__
   1993         raise cls("{!s}: Exception raised while transforming parameter `{:s}` with value {!r}".format('.'.join([f.__module__, f.__name__]), argname, kwds[argname]))
-> 1994 return F(*res, **kwds)

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\database.py:633, in functions.list(cls, **type)
    631     refs = max(len(xref.up(ea)), refs)
    632     lvars = max(Fcount_lvars(func) if idaapi.get_frame(ea) else 0, lvars)
--> 633     avars = max(Fcount_avars(func), avars)
    635     listable.append(ea)
    637 # Collect the number of digits for everything from the first pass

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\_utils.py:56, in <lambda>(*a)
     54 first, second, third, last = operator.itemgetter(0), operator.itemgetter(1), operator.itemgetter(2), operator.itemgetter(-1)
     55 # return a closure that executes a list of functions one after another from left-to-right.
---> 56 fcompose = lambda *Fa: functools.reduce(lambda F1, F2: lambda *a: F1(F2(*a)), builtins.reversed(Fa))
     57 # return a closure that executes function `F` whilst discarding any arguments passed to it.
     58 fdiscard = lambda F, *a, **k: lambda *ap, **kp: F(*a, **k)

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\_utils.py:56, in <lambda>(*a)
     54 first, second, third, last = operator.itemgetter(0), operator.itemgetter(1), operator.itemgetter(2), operator.itemgetter(-1)
     55 # return a closure that executes a list of functions one after another from left-to-right.
---> 56 fcompose = lambda *Fa: functools.reduce(lambda F1, F2: lambda *a: F1(F2(*a)), builtins.reversed(Fa))
     57 # return a closure that executes function `F` whilst discarding any arguments passed to it.
     58 fdiscard = lambda F, *a, **k: lambda *ap, **kp: F(*a, **k)

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\_utils.py:56, in <lambda>(*a)
     54 first, second, third, last = operator.itemgetter(0), operator.itemgetter(1), operator.itemgetter(2), operator.itemgetter(-1)
     55 # return a closure that executes a list of functions one after another from left-to-right.
---> 56 fcompose = lambda *Fa: functools.reduce(lambda F1, F2: lambda *a: F1(F2(*a)), builtins.reversed(Fa))
     57 # return a closure that executes function `F` whilst discarding any arguments passed to it.
     58 fdiscard = lambda F, *a, **k: lambda *ap, **kp: F(*a, **k)

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\function.py:2650, in frame.arguments.iterate(cls, func)
   2646     return
   2648 # If we got here, then we have type information that we can grab out
   2649 # of the given address. Once we have it, rip the details out o it.
-> 2650 tinfo = type(ea)
   2651 _, ftd = interface.tinfo.function_details(ea, tinfo)
   2653 # Now we just need to iterate through our parameters collecting the
   2654 # raw location information for all of them. We preserve the type
   2655 # information in case we're unable to find the argument in a member.

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\_utils.py:694, in function.__new__(*arguments, **keywords)
    691 # Now we have a matching callable for the user's parameters, and we just need
    692 # to unpack our individual parameters and dispatch to the callable with them.
    693 parameters, wild_parameters, keyword_parameters = result_parameters
--> 694 return result_callable(*itertools.chain(parameters, wild_parameters), **keyword_parameters)

File ~\AppData\Roaming\Hex-Rays\IDA Pro\base\function.py:3232, in type.__new__(cls, func)
   3229 # If we weren't able to create the missing type, then we need to abort. This shouldn't
   3230 # be possible at all whatsoever, but perhaps some database state is preventing us.
   3231 if not missing:
-> 3232     raise E.DisassemblerError(u"{:s}({:#x}) : Unable to create a dummy function type to return for the for the specified function ({:#x}).".format('.'.join([__name__, cls.__name__]), ea, ea))
   3234 logging.warning(u"{:s}({:#x}) : Unable to guess the missing type for the function at {:#x} due to error ({:d}) which will result in an empty function type (\"{:s}\") being returned.".format('.'.join([__name__, cls.__name__]), ea, ea, idaapi.GUESS_FUNC_FAILED, utils.string.escape("{!s}".format(missing), '"')))
   3235 return missing

DisassemblerError: function.type(0x401029) : Unable to create a dummy function type to return for the for the specified function (0x401029).