From 44a5fe009a22550960688e9a5b27d44f1e8a78e8 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Fri, 24 Jul 2020 17:20:37 +0200 Subject: [PATCH] C++: Output il2cpp-api-functions.h with unavailable exports elided --- .../Cpp/UnityHeaders/UnityHeaders.cs | 10 ++++--- .../Outputs/CppScaffolding.cs | 26 ++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs b/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs index b7d601d..e2710ed 100644 --- a/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs +++ b/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs @@ -173,11 +173,15 @@ namespace Il2CppInspector.Cpp.UnityHeaders } // Convert il2cpp-api-functions.h from "DO_API(r, n, p)" to "typedef r (*n)(p)" - internal static string GetTypedefsFromAPIHeader(string text) { - var rgx = new Regex(@"^DO_API(?:_NO_RETURN)?\((.*?),(.*?),\s*\((.*?)\)\s*\);", RegexOptions.Multiline); - return rgx.Replace(text, "typedef $1 (*$2)($3);"); + private static readonly Regex APILineRegex = new Regex(@"^DO_API(?:_NO_RETURN)?\((.*?),(.*?),\s*\((.*?)\)\s*\);", RegexOptions.Multiline); + + internal static string GetFunctionNameFromAPILine(string line) { + var match = APILineRegex.Match(line); + return match.Success ? match.Groups[2].ToString().Trim() : string.Empty; } + internal static string GetTypedefsFromAPIHeader(string text) => APILineRegex.Replace(text, "typedef $1 (*$2)($3);"); + // Get a list of function names from il2cpp-api-functions.h, taking #ifs into account private static IEnumerable GetFunctionNamesFromAPIHeaderText(string text) { var defText = GetTypedefsFromAPIHeader(text); diff --git a/Il2CppInspector.Common/Outputs/CppScaffolding.cs b/Il2CppInspector.Common/Outputs/CppScaffolding.cs index ab806fd..b661336 100644 --- a/Il2CppInspector.Common/Outputs/CppScaffolding.cs +++ b/Il2CppInspector.Common/Outputs/CppScaffolding.cs @@ -9,6 +9,7 @@ using System.Text; using System.Text.RegularExpressions; using Il2CppInspector.Reflection; using Il2CppInspector.Cpp; +using Il2CppInspector.Cpp.UnityHeaders; using Il2CppInspector.Model; using Il2CppInspector.Properties; @@ -50,6 +51,27 @@ namespace Il2CppInspector.Outputs writer.Close(); + // Write selected Unity API function file to il2cpp-api-functions.h + // (this is a copy of the header file from an actual Unity install) + var il2cppApiFile = Path.Combine(outputPath, "il2cpp-api-functions.h"); + var apiHeaderText = model.UnityHeaders.GetAPIHeaderText(); + + using var fsApi = new FileStream(il2cppApiFile, FileMode.Create); + writer = new StreamWriter(fsApi, Encoding.UTF8); + + writeHeader(); + + // Elide APIs that aren't in the binary to avoid compile errors + foreach (var line in apiHeaderText.Split('\n')) { + var fnName = UnityHeaders.GetFunctionNameFromAPILine(line); + + if (string.IsNullOrEmpty(fnName)) + writer.WriteLine(line); + else if (model.AvailableAPIs.ContainsKey(fnName)) + writer.WriteLine(line); + } + writer.Close(); + // Write API function pointers to il2cpp-function-ptr.h var il2cppFnPtrFile = Path.Combine(outputPath, "il2cpp-function-ptr.h"); @@ -59,7 +81,9 @@ namespace Il2CppInspector.Outputs writeHeader(); writeSectionHeader("IL2CPP API function pointers"); - // TODO: Use model.APIExports instead once it is implemented + // We could use model.AvailableAPIs here but that would exclude outputting the address + // of API exports which for some reason aren't defined in our selected API header, + // so although it doesn't affect the C++ compilation, we use GetAPIExports() instead for completeness var exports = model.Package.Binary.GetAPIExports(); foreach (var export in exports) {