Browse Source

Add uname libc call on Unix systems as platform check
MonoMod's PlatformHelper call causes issues as it calls Process.Create (which breaks in Unity 4.x), so we use a libc uname call to do the same thing without dying

Bepis 4 years ago
parent
commit
7647862bf4

+ 7 - 6
BepInEx.Preloader/BepInEx.Preloader.csproj

@@ -39,13 +39,13 @@
     <Reference Include="Mono.Cecil.Rocks, Version=0.10.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
       <HintPath>$(SolutionDir)\packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Rocks.dll</HintPath>
     </Reference>
-    <Reference Include="MonoMod.RuntimeDetour, Version=20.8.3.5, Culture=neutral, PublicKeyToken=null">
-      <HintPath>..\packages\MonoMod.RuntimeDetour.20.8.3.5\lib\net35\MonoMod.RuntimeDetour.dll</HintPath>
-      <Private>True</Private>
+    <Reference Include="MonoMod.RuntimeDetour, Version=20.8.3.5, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\MonoMod\MonoMod.RuntimeDetour\bin\Release\net35\MonoMod.RuntimeDetour.dll</HintPath>
     </Reference>
-    <Reference Include="MonoMod.Utils, Version=20.8.3.5, Culture=neutral, PublicKeyToken=null">
-      <HintPath>..\packages\MonoMod.Utils.20.8.3.5\lib\net35\MonoMod.Utils.dll</HintPath>
-      <Private>True</Private>
+    <Reference Include="MonoMod.Utils, Version=20.8.3.5, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\MonoMod\MonoMod.RuntimeDetour\bin\Release\net35\MonoMod.Utils.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
@@ -55,6 +55,7 @@
     <Compile Include="Patching\AssemblyPatcher.cs" />
     <Compile Include="Entrypoint.cs" />
     <Compile Include="Patching\PatcherPlugin.cs" />
+    <Compile Include="Platform.cs" />
     <Compile Include="RuntimeFixes\ConsoleSetOutFix.cs" />
     <Compile Include="RuntimeFixes\TraceFix.cs" />
     <Compile Include="Preloader.cs" />

+ 2 - 0
BepInEx.Preloader/Entrypoint.cs

@@ -10,6 +10,8 @@ namespace BepInEx.Preloader
 	{
 		public static void PreloaderPreMain()
 		{
+			PlatformUtils.SetPlatform();
+
 			string bepinPath = Utility.ParentDirectory(Path.GetFullPath(EnvVars.DOORSTOP_INVOKE_DLL_PATH), 2);
 
 			Paths.SetExecutablePath(EnvVars.DOORSTOP_PROCESS_PATH, bepinPath, EnvVars.DOORSTOP_MANAGED_FOLDER_DIR);

+ 153 - 0
BepInEx.Preloader/Platform.cs

@@ -0,0 +1,153 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using MonoMod.Utils;
+
+namespace BepInEx.Preloader
+{
+	internal static class PlatformUtils
+	{
+		[StructLayout(LayoutKind.Sequential, Pack = 1)]
+		public struct utsname_osx
+		{
+			private const int osx_utslen = 256;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
+			public string sysname;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
+			public string nodename;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
+			public string release;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
+			public string version;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = osx_utslen)]
+			public string machine;
+		}
+
+		[StructLayout(LayoutKind.Sequential, Pack = 1)]
+		public struct utsname_linux
+		{
+			private const int linux_utslen = 65;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
+			public string sysname;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
+			public string nodename;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
+			public string release;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
+			public string version;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
+			public string machine;
+
+			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = linux_utslen)]
+			public string domainname;
+		}
+
+        [DllImport("libc.so.6", EntryPoint = "uname", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+		private static extern IntPtr uname_linux(ref utsname_linux utsname);
+
+		[DllImport("/usr/lib/libSystem.dylib", EntryPoint = "uname", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+		private static extern IntPtr uname_osx(ref utsname_osx utsname);
+
+        /// <summary>
+        /// Recreation of MonoMod's PlatformHelper.DeterminePlatform method, but with libc calls instead of creating processes.
+        /// </summary>
+        public static void SetPlatform()
+		{
+            var current = Platform.Unknown;
+
+            // For old Mono, get from a private property to accurately get the platform.
+            // static extern PlatformID Platform
+            PropertyInfo p_Platform = typeof(Environment).GetProperty("Platform", BindingFlags.NonPublic | BindingFlags.Static);
+            string platID;
+            if (p_Platform != null)
+            {
+                platID = p_Platform.GetValue(null, new object[0]).ToString();
+            }
+            else
+            {
+                // For .NET and newer Mono, use the usual value.
+                platID = Environment.OSVersion.Platform.ToString();
+            }
+            platID = platID.ToLowerInvariant();
+
+            if (platID.Contains("win"))
+            {
+                current = Platform.Windows;
+            }
+            else if (platID.Contains("mac") || platID.Contains("osx"))
+            {
+                current = Platform.MacOS;
+            }
+            else if (platID.Contains("lin") || platID.Contains("unix"))
+            {
+                current = Platform.Linux;
+            }
+
+            if (Is(current, Platform.Linux) && Directory.Exists("/data") && File.Exists("/system/build.prop"))
+            {
+                current = Platform.Android;
+            }
+			else if (Is(current, Platform.Unix) && Directory.Exists("/Applications") && Directory.Exists("/System"))
+			{
+				current = Platform.iOS;
+			}
+
+			// Is64BitOperatingSystem has been added in .NET Framework 4.0
+			MethodInfo m_get_Is64BitOperatingSystem = typeof(Environment).GetProperty("Is64BitOperatingSystem")?.GetGetMethod();
+            if (m_get_Is64BitOperatingSystem != null)
+                current |= (((bool)m_get_Is64BitOperatingSystem.Invoke(null, new object[0])) ? Platform.Bits64 : 0);
+            else
+                current |= (IntPtr.Size >= 8 ? Platform.Bits64 : 0);
+
+			File.AppendAllText("scuffed_debug.log", $"{platID}\n{current}");
+
+			if ((Is(current, Platform.MacOS) || Is(current, Platform.Linux)) && Type.GetType("Mono.Runtime") != null)
+            {
+				string arch;
+				IntPtr result;
+
+				if (Is(current, Platform.MacOS))
+				{
+					utsname_osx utsname_osx = new utsname_osx();
+					result = uname_osx(ref utsname_osx);
+					arch = utsname_osx.machine;
+				}
+				else
+				{
+					// Linux
+					utsname_linux utsname_linux = new utsname_linux();
+					result = uname_linux(ref utsname_linux);
+					arch = utsname_linux.machine;
+				}
+
+				if (result == IntPtr.Zero && (arch.StartsWith("aarch") || arch.StartsWith("arm")))
+					current |= Platform.ARM;
+			}
+            else
+            {
+                // Detect ARM based on PE info or uname.
+                typeof(object).Module.GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine);
+                if (machine == (ImageFileMachine)0x01C4 /* ARM, .NET Framework 4.5 */)
+                    current |= Platform.ARM;
+            }
+
+			PlatformHelper.Current = current;
+		}
+
+		private static bool Is(Platform current, Platform expected)
+		{
+			return (current & expected) == expected;
+		}
+    }
+}

+ 2 - 1
BepInEx.Preloader/Preloader.cs

@@ -68,6 +68,7 @@ namespace BepInEx.Preloader
 				Logger.LogInfo($"Running under Unity v{GetUnityVersion()}");
 				Logger.LogInfo($"CLR runtime version: {Environment.Version}");
 				Logger.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}");
+				Logger.LogInfo($"System platform: {PlatformHelper.Current}");
 
 				if (runtimePatchException != null)
 					Logger.LogWarning($"Failed to apply runtime patches for Mono. See more info in the output log. Error message: {runtimePatchException.Message}");
@@ -236,7 +237,7 @@ namespace BepInEx.Preloader
 
 		public static string GetUnityVersion()
 		{
-			if (Utility.CurrentOs == Platform.Windows)
+			if (PlatformHelper.Is(Platform.Windows))
 				return FileVersionInfo.GetVersionInfo(Paths.ExecutablePath).FileVersion;
 
 			return $"Unknown ({(IsPostUnity2017 ? "post" : "pre")}-2017)";

+ 2 - 2
BepInEx.Preloader/RuntimeFixes/XTermFix.cs

@@ -13,7 +13,7 @@ namespace BepInEx.Preloader.RuntimeFixes
 	{
 		public static void Apply()
 		{
-			if (Utility.CurrentOs == Platform.Windows)
+			if (PlatformHelper.Is(Platform.Windows))
 				return;
 
 			if (typeof(Console).Assembly.GetType("System.ConsoleDriver") == null)
@@ -34,7 +34,7 @@ namespace BepInEx.Preloader.RuntimeFixes
 			// Because Doorstop does not support ARM at the moment, we can get away with just forcing x86 detour platform.
 			// TODO: Figure out a way to detect ARM on Unix without running Process.Start
 			DetourHelper.Native = new DetourNativeX86Platform();
-
+			
 			var harmony = new HarmonyLib.Harmony("com.bepinex.xtermfix");
 
 			harmony.Patch(AccessTools.Method("System.TermInfoReader:ReadHeader"),

+ 1 - 1
BepInEx/Bootstrap/Chainloader.cs

@@ -97,7 +97,7 @@ namespace BepInEx.Bootstrap
 				Logger.Sources.Add(new UnityLogSource());
 			Logger.Listeners.Add(new UnityLogListener());
 
-			if (Utility.CurrentOs == Platform.Linux)
+			if (PlatformHelper.Is(Platform.Unix))
 			{
 				Logger.LogInfo($"Detected Unity version: v{Application.unityVersion}");
 			}

+ 6 - 13
BepInEx/Console/ConsoleManager.cs

@@ -32,20 +32,13 @@ namespace BepInEx
 
 		public static void Initialize(bool alreadyActive)
 		{
-			switch (Utility.CurrentOs)
+			if (PlatformHelper.Is(Platform.Unix))
 			{
-				case Platform.MacOS:
-				case Platform.Linux:
-				{
-					Driver = new LinuxConsoleDriver();
-					break;
-				}
-
-				case Platform.Windows:
-				{
-					Driver = new WindowsConsoleDriver();
-					break;
-				}
+				Driver = new LinuxConsoleDriver();
+			}
+			else if (PlatformHelper.Is(Platform.Windows))
+			{
+				Driver = new WindowsConsoleDriver();
 			}
 
 			Driver.Initialize(alreadyActive);

+ 1 - 1
BepInEx/Paths.cs

@@ -14,7 +14,7 @@ namespace BepInEx
 			ExecutablePath = executablePath;
 			ProcessName = Path.GetFileNameWithoutExtension(executablePath);
 
-			GameRootPath = Utility.CurrentOs == Platform.MacOS
+			GameRootPath = PlatformHelper.Is(Platform.MacOS)
 				? Utility.ParentDirectory(executablePath, 4)
 				: Path.GetDirectoryName(executablePath);
 

+ 0 - 28
BepInEx/Utility.cs

@@ -44,11 +44,6 @@ namespace BepInEx
 			sreEnabled = true;
 			return sreEnabled.Value;
 		}
-		
-		static Utility()
-		{
-			CheckPlatform();
-		}
 
 		/// <summary>
 		/// Try to perform an action.
@@ -299,28 +294,5 @@ namespace BepInEx
 				return false;
 			}
 		}
-
-		// Adapted from https://github.com/MonoMod/MonoMod.Common/blob/master/Utils/PlatformHelper.cs#L13
-		private static void CheckPlatform()
-		{
-			var pPlatform = typeof(Environment).GetProperty("Platform", BindingFlags.NonPublic | BindingFlags.Static);
-			string platId = pPlatform != null ? pPlatform.GetValue(null, new object[0]).ToString() : Environment.OSVersion.Platform.ToString();
-			platId = platId.ToLowerInvariant();
-
-			var cur = Platform.Unknown;
-			if (platId.Contains("win"))
-				cur = Platform.Windows;
-			else if (platId.Contains("mac") || platId.Contains("osx"))
-				cur = Platform.MacOS;
-			else if (platId.Contains("lin") || platId.Contains("unix"))
-				cur = Platform.Linux;
-
-			CurrentOs = cur;
-		}
-
-		/// <summary>
-		/// Current OS BepInEx is running on.
-		/// </summary>
-		public static Platform CurrentOs { get; private set; }
 	}
 }