#pragma once #include #include #include #include #include #include #include struct FunctionParams { std::vector param_types; }; struct ThunkedCallback : FunctionParams { clang::QualType return_type; bool is_stub = false; // Callback will be replaced by a stub that calls std::abort bool is_guest = false; // Callback will never be called on the host bool is_variadic = false; }; /** * Guest<->Host transition point. * * These are normally used to translate the public API of the guest to host * function calls (ThunkedAPIFunction), but a thunk library may also define * internal thunks that don't correspond to any function in the implemented * API. */ struct ThunkedFunction : FunctionParams { std::string function_name; clang::QualType return_type; // If true, param_types contains an extra size_t and the valist for marshalling through an internal function bool is_variadic = false; // If true, the unpacking function will call a custom fexfn_impl function // to be provided manually instead of calling the host library function // directly. // This is implied e.g. for thunks generated for variadic functions bool custom_host_impl = false; std::string GetOriginalFunctionName() const { const std::string suffix = "_internal"; assert(function_name.length() > suffix.size()); assert((std::string_view { &*function_name.end() - suffix.size(), suffix.size() } == suffix)); return function_name.substr(0, function_name.size() - suffix.size()); } // Maps parameter index to ThunkedCallback std::unordered_map callbacks; clang::FunctionDecl* decl; }; /** * Function that is part of the API of the thunked library. * * For each of these, there is: * - A publicly visible guest entrypoint (usually auto-generated but may be manually defined) * - A pointer to the native host library function loaded through dlsym (or a user-provided function specified via host_loader) * - A ThunkedFunction with the same function_name (possibly suffixed with _internal) */ struct ThunkedAPIFunction : FunctionParams { std::string function_name; clang::QualType return_type; // name of the function to load the native host symbol with std::string host_loader; // If true, no guest-side implementation of this function will be autogenerated bool custom_guest_impl; bool is_variadic; // Index of the symbol table to store this export in (see guest_symtables). // If empty, a library export is created, otherwise the function is entered into a function pointer array std::optional symtable_namespace; }; struct NamespaceInfo { clang::DeclContext* context; std::string name; // Function to load native host library functions with. // This function must be defined manually with the signature "void* func(void*, const char*)" std::string host_loader; bool generate_guest_symtable; bool indirect_guest_calls; }; class AnalysisAction : public clang::ASTFrontendAction { public: AnalysisAction() { decl_contexts.push_back(nullptr); // global namespace (replaced by getTranslationUnitDecl later) } void ExecuteAction() override; std::unique_ptr CreateASTConsumer(clang::CompilerInstance&, clang::StringRef /*file*/) override; protected: // Build the internal API representation by processing fex_gen_config and other annotated entities void ParseInterface(clang::ASTContext&); // Called from ExecuteAction() after parsing is complete virtual void EmitOutput(clang::ASTContext&) {}; std::vector decl_contexts; std::vector thunks; std::vector thunked_api; std::unordered_set funcptr_types; std::optional lib_version; std::vector namespaces; };