dragonffi icon indicating copy to clipboard operation
dragonffi copied to clipboard

Printing a struct and function type signatures?

Open billtohara opened this issue 7 years ago • 5 comments

Is it possible to print the signature of a loaded function? For example, gettimeofday is tricky because the arguments are pointers to structs. Is it possible to get this signature back:

int gettimeofday(struct timeval *restrict tp, void *restrict tzp);

And even better that timeval is this? (taken from sys/time.h)

struct timeval {
             time_t       tv_sec;   /* seconds since Jan. 1, 1970 */
             suseconds_t  tv_usec;  /* and microseconds */
     };

I get stuck in not knowing how to proceed from the "QualType" for the arguments.

   >>> import pydffi
   >>> FFI = pydffi.FFI()
   >>> CU = FFI.cdef("#include <sys/time.h>")
   >>> CU.funcs.gettimeofday.type().returnType.kind
   BasicKind.Int
   >>> CU.funcs.gettimeofday.type().params[0]
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: Unable to convert function return value to a Python type! The signature was
   	(arg0: pydffi.FunctionType) -> List[dffi::QualType].   

billtohara avatar May 20 '18 04:05 billtohara

Hello!

Automatic documentation generation does not exist for the moment, but could indeed be a really nice feature!

About structure introspection, you can use dir on the structure type to get the list of fields:

print(dir(CU.types.timeval))

I agree that prettyprinting of types also needs to be exposed.

About calling gettimeofday with dragonffi, here is an example:

import pydffi
FFI = pydffi.FFI()
CU = FFI.cdef("#include <sys/time.h>")
print(dir(CU.types.timeval))
timeval = CU.types.timeval()
CU.funcs.gettimeofday(FFI.ptr(timeval), FFI.ptr(CU.types.timezone)())
print(timeval.tv_sec)
print(timeval.tv_usec)

aguinet avatar May 20 '18 08:05 aguinet

Thank you! I appreciate the examples (it did help clear up something about my real internal use case). In terms of prettyprinting the function signatures, any pointers on where to begin to try to add that in the implementation? If I could get the function signature, even without the ability to print the struct itself, that would already be a big help. Right now the best I can manage prints as pointers to some autogenerated ffi struct, seemingly because the actual struct is seen as opaque, and I can't seem to find the name of the struct to print that.

billtohara avatar May 20 '18 15:05 billtohara

Which format would you like function signatures and types to be exposed? The first "easy" thing to do is to propose an API based on tthe existing type printer (lib/types_printer.h). The one thing is that types are not directly linked to their names, so the printer won't print them.

Another thing that could be done is dumping the necessary types in JSON , and process them with any external tool.

For the record, I am rewriting the way types are handled to factorize code between the DWARF parsing (incoming feature) and the actual parsing from the LLVM IR. That being said, we can still prototype this something.

If I can ask, what's your intended use case?

aguinet avatar May 22 '18 11:05 aguinet

Ideally, something that would be acceptable to the C compiler. I'm phrasing it like that to try to say it without implying that they need to be char for char equivalent to the original declaration. Essentially, so long as a C compiler would compile it and make the correct call, that's more than good enough.

JSON would be fine. In fact anything that I can further process. I'm currently stymied by not being able to match up the names (e.g. for structs).

The test case is an internal testing tool. I'm trying to take headers and libraries, make various automatically generated testing calls and then produce reduced test cases. It would be very nice to be able to print messages about functions without having to go back and look at the original headers (which can be monsterous, some auto generated in particular).

billtohara avatar May 23 '18 22:05 billtohara

Ideally, something that would be acceptable to the C compiler. I'm phrasing it like that to try to say it without implying that they need to be char for char equivalent to the original declaration. Essentially, so long as a C compiler would compile it and make the correct call, that's more than good enough.

Okay! So the output of the current wrapper generator might already do what you need. Here is an example:

For this C function/types:

struct A {
  int a;
  float b;
};

void print(struct A a) { printf("%d %f\n", a.a, a.b); }

it would produce, for the print function:

struct __dffi_ty_0 {
  int __Field_0;
  float __Field_1;
};
void __dffi_wrapper_0(void ( __attribute__((cdecl)) (*__FPtr))(struct __dffi_ty_0),void (*__Ret),void** __Args) {
  (__FPtr)(*((struct __dffi_ty_0 (*))__Args[0]));
}

This basically generates a wrapper around the function type of print, to be able call it with a list of void* generic arguments (that are casted within the wrapper).

Note that, for your use case, you can use dragonffi directly in C++ to make calls through these wrappers. You have examples for instance in the tests/compile.cpp or in the tests/cdef.cpp files.

If this doesn't completely fit your need, and you have an example of the output you would like, I think we could figure out an API to implement to do it :)

aguinet avatar May 24 '18 07:05 aguinet