ghidra: undefined parameter types in high function signature recovery

Describe the bug The function fons__tt_getPixelHeightScale in the clang executable (attached) has 2 parameters i.e. pointer and float. The signature of the function in the source code is: float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size) Whereas ghidra recovers param1 as undefined4 and param2 as undefined8. I am getting the parameters from the Local Symbol Map after lifting the function as High Function. Can someone explain, why is the output from ghidra not compatible with the source?

To Reproduce Steps to reproduce the behavior:

  1. Run ghidra in headless mode and execute the python script below:

  2.  res = ifc.decompileFunction(func, 60, monitor)
     high_func = res.getHighFunction()
     if high_func != None:
         lsm = high_func.getLocalSymbolMap()
         symbols = lsm.getSymbols()
         for i, symbol in enumerate(symbols):
             if symbol.isParameter():
                  fw.write("paramname: {}, paramtype: {}, paramsize:{}\n".format(symbol.name,str(symbol.dataType),str(symbol.getSize()))) 
    
    
  3. the output of the above code is as follows:

   paramname: param_1, paramtype: undefined4, paramsize:4
   paramname: param_2, paramtype: undefined8, paramsize:8

Expected behavior

   paramname: param_1, paramtype: FONSttFontImpl *, paramsize:8
   paramname: param_2, paramtype: float, paramsize:4
or at least
   paramname: param_1, paramtype: undefined8 , paramsize:8
   paramname: param_2, paramtype: float, paramsize:4

Is there anyway to improve the recovery from ghidra? Screenshots The executable is attached. mrpt__libmrpt-nanogui_clang_O0.zip

**Environment **

Additional context

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 16 (7 by maintainers)

Most upvoted comments

If I understand correctly, the concern is that Ghidra is recovering the function signature float func(void *, float) as float func(float, void *).

While these two function signatures are distinct in C, they are not distinct under any of the major x86-64 ABIs. On both Linux (SysV) and Windows, the void * will be passed in a general purpose register (RDI on Linux, RCX on Windows), and the float will be passed in XMM0. They are therefore indistinguishable from the perspective of the calling convention. If Ghidra does not have access to detailed function signature information (from e.g. C++ demangling or DWARF debug data), it will simply guess that there’s one float parameter and one integer parameter. There’s no way to know how those two parameters should be ordered relative to each other from the assembly code alone.

The order in which the arguments are loaded in the caller, or stored in the callee, cannot be used to definitely determine parameter order. Compilers are free to load arguments in any order, and are free to store the arguments as local variables on the stack any way they like (or even not at all!). Therefore, Ghidra cannot rely on those kinds of signals to recover parameter order.