private static bool IsMethodEligible(MethodInfo method) { if (method.IsGenericMethod || method.IsGenericMethodDefinition) { return(false); } if (method.Name == "Finalize") { return(false); } if (method.IsStatic || method.IsAbstract) { return(false); } if (!IsTypeSupported(method.ReturnType)) { LogSupport.Warning($"Method {method} on type {method.DeclaringType} has unsupported return type {method.ReturnType}"); return(false); } foreach (var parameter in method.GetParameters()) { var parameterType = parameter.ParameterType; if (!IsTypeSupported(parameterType)) { LogSupport.Warning($"Method {method} on type {method.DeclaringType} has unsupported parameter {parameter} of type {parameterType}"); return(false); } } return(true); }
private static bool IsMethodEligible(MethodInfo method) { if (method.IsGenericMethod || method.IsGenericMethodDefinition) { return(false); } if (method.Name == "Finalize") { return(false); } if (method.IsStatic || method.IsAbstract) { return(false); } if (method.CustomAttributes.Any(it => it.AttributeType == typeof(HideFromIl2CppAttribute))) { return(false); } if ( method.DeclaringType != null && method.DeclaringType.GetProperties() .Where(property => property.GetAccessors(true).Contains(method)) .Any(property => property.CustomAttributes.Any(it => it.AttributeType == typeof(HideFromIl2CppAttribute))) ) { return(false); } if (!IsTypeSupported(method.ReturnType)) { LogSupport.Warning($"Method {method} on type {method.DeclaringType} has unsupported return type {method.ReturnType}"); return(false); } foreach (var parameter in method.GetParameters()) { var parameterType = parameter.ParameterType; if (!IsTypeSupported(parameterType)) { LogSupport.Warning($"Method {method} on type {method.DeclaringType} has unsupported parameter {parameter} of type {parameterType}"); return(false); } } return(true); }
public static void GenerateInvokerMethodBody(MethodDefinition newMethod, FieldDefinition delegateField, TypeDefinition delegateType, TypeRewriteContext enclosingType, AssemblyKnownImports imports) { var body = newMethod.Body.GetILProcessor(); body.Emit(OpCodes.Ldsfld, delegateField); if (newMethod.HasThis) { body.Emit(OpCodes.Ldarg_0); body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointerNotNull); } var argOffset = newMethod.HasThis ? 1 : 0; for (var i = 0; i < newMethod.Parameters.Count; i++) { var param = newMethod.Parameters[i]; var paramType = param.ParameterType; if (paramType.IsValueType || paramType.IsByReference && paramType.GetElementType().IsValueType) { body.Emit(OpCodes.Ldarg, i + argOffset); } else { body.EmitObjectToPointer(param.ParameterType, param.ParameterType, enclosingType, i + argOffset, false, true, true, out var refVar); if (refVar != null) { LogSupport.Warning($"Method {newMethod} has a reference-typed ref parameter, this will be ignored"); } } } body.Emit(OpCodes.Call, delegateType.Methods.Single(it => it.Name == "Invoke")); if (!newMethod.ReturnType.IsValueType) { var pointerVar = new VariableDefinition(imports.IntPtr); newMethod.Body.Variables.Add(pointerVar); body.Emit(OpCodes.Stloc, pointerVar); var loadInstr = body.Create(OpCodes.Ldloc, pointerVar); body.EmitPointerToObject(newMethod.ReturnType, newMethod.ReturnType, enclosingType, loadInstr, false, false); } body.Emit(OpCodes.Ret); }
public static void Main(UnhollowerOptions options) { if (string.IsNullOrEmpty(options.SourceDir)) { Console.WriteLine("No input dir specified; use -h for help"); return; } if (string.IsNullOrEmpty(options.OutputDir)) { Console.WriteLine("No target dir specified; use -h for help"); return; } if (string.IsNullOrEmpty(options.MscorlibPath)) { Console.WriteLine("No mscorlib specified; use -h for help"); return; } if (!Directory.Exists(options.OutputDir)) { Directory.CreateDirectory(options.OutputDir); } RewriteGlobalContext rewriteContext; using (new TimingCookie("Reading assemblies")) rewriteContext = new RewriteGlobalContext(options, Directory.EnumerateFiles(options.SourceDir, "*.dll")); using (new TimingCookie("Computing renames")) Pass05CreateRenameGroups.DoPass(rewriteContext); using (new TimingCookie("Creating typedefs")) Pass10CreateTypedefs.DoPass(rewriteContext); using (new TimingCookie("Computing struct blittability")) Pass11ComputeTypeSpecifics.DoPass(rewriteContext); using (new TimingCookie("Filling typedefs")) Pass12FillTypedefs.DoPass(rewriteContext); using (new TimingCookie("Filling generic constraints")) Pass13FillGenericConstraints.DoPass(rewriteContext); using (new TimingCookie("Creating members")) Pass15GenerateMemberContexts.DoPass(rewriteContext); using (new TimingCookie("Scanning method cross-references")) Pass16ScanMethodRefs.DoPass(rewriteContext, options); using (new TimingCookie("Finalizing method declarations")) Pass18FinalizeMethodContexts.DoPass(rewriteContext); LogSupport.Info($"{Pass18FinalizeMethodContexts.TotalPotentiallyDeadMethods} total potentially dead methods"); using (new TimingCookie("Filling method parameters")) Pass19CopyMethodParameters.DoPass(rewriteContext); using (new TimingCookie("Creating static constructors")) Pass20GenerateStaticConstructors.DoPass(rewriteContext); using (new TimingCookie("Creating value type fields")) Pass21GenerateValueTypeFields.DoPass(rewriteContext); using (new TimingCookie("Creating enums")) Pass22GenerateEnums.DoPass(rewriteContext); using (new TimingCookie("Creating IntPtr constructors")) Pass23GeneratePointerConstructors.DoPass(rewriteContext); using (new TimingCookie("Creating type getters")) Pass24GenerateTypeStaticGetters.DoPass(rewriteContext); using (new TimingCookie("Creating non-blittable struct constructors")) Pass25GenerateNonBlittableValueTypeDefaultCtors.DoPass(rewriteContext); using (new TimingCookie("Creating generic method static constructors")) Pass30GenerateGenericMethodStoreConstructors.DoPass(rewriteContext); using (new TimingCookie("Creating field accessors")) Pass40GenerateFieldAccessors.DoPass(rewriteContext); using (new TimingCookie("Filling methods")) Pass50GenerateMethods.DoPass(rewriteContext); using (new TimingCookie("Generating implicit conversions")) Pass60AddImplicitConversions.DoPass(rewriteContext); using (new TimingCookie("Creating properties")) Pass70GenerateProperties.DoPass(rewriteContext); if (options.UnityBaseLibsDir != null) { using (new TimingCookie("Unstripping types")) Pass79UnstripTypes.DoPass(rewriteContext); using (new TimingCookie("Unstripping fields")) Pass80UnstripFields.DoPass(rewriteContext); using (new TimingCookie("Unstripping methods")) Pass80UnstripMethods.DoPass(rewriteContext); using (new TimingCookie("Unstripping method bodies")) Pass81FillUnstrippedMethodBodies.DoPass(rewriteContext); } else { LogSupport.Warning("Not performing unstripping as unity libs are not specified"); } using (new TimingCookie("Generating forwarded types")) Pass89GenerateForwarders.DoPass(rewriteContext); using (new TimingCookie("Writing xref cache")) Pass89GenerateMethodXrefCache.DoPass(rewriteContext, options); using (new TimingCookie("Writing assemblies")) Pass90WriteToDisk.DoPass(rewriteContext, options); using (new TimingCookie("Writing method pointer map")) Pass91GenerateMethodPointerMap.DoPass(rewriteContext, options); if (!options.NoCopyUnhollowerLibs) { File.Copy(typeof(IL2CPP).Assembly.Location, Path.Combine(options.OutputDir, typeof(IL2CPP).Assembly.GetName().Name + ".dll"), true); File.Copy(typeof(RuntimeLibMarker).Assembly.Location, Path.Combine(options.OutputDir, typeof(RuntimeLibMarker).Assembly.GetName().Name + ".dll"), true); File.Copy(typeof(Decoder).Assembly.Location, Path.Combine(options.OutputDir, typeof(Decoder).Assembly.GetName().Name + ".dll"), true); } LogSupport.Info("Done!"); rewriteContext.Dispose(); }