public void SymbolExists() { var failed_api = new HashSet <string> (); Errors = 0; int c = 0, n = 0; foreach (MethodInfo mi in pinvokeQuery) { if (LogProgress) { Console.WriteLine("{0}. {1}", c++, mi); } var dllimport = mi.GetCustomAttribute <DllImportAttribute> (); string libname = dllimport.Value; switch (libname) { case "__Internal": continue; case "System.Native": case "System.Security.Cryptography.Native.Apple": case "System.Net.Security.Native": if (MonoNativeConfig.LinkMode == MonoNativeLinkMode.None) { continue; } #if __IOS__ libname = MonoNativeConfig.GetPInvokeLibraryName(MonoNativeFlavor.Compat, MonoNativeConfig.LinkMode); #else libname = null; #endif break; } if (SkipLibrary(libname)) { continue; } string path = FindLibrary(libname, requiresFullPath: true); string name = dllimport.EntryPoint ?? mi.Name; if (Skip(name)) { continue; } IntPtr lib = Dlfcn.dlopen(path, 0); if (Dlfcn.GetIndirect(lib, name) == IntPtr.Zero && !failed_api.Contains(name)) { ReportError("Could not find the field '{0}' in {1}", name, path); failed_api.Add(name); } Dlfcn.dlclose(lib); n++; } Assert.AreEqual(0, Errors, "{0} errors found in {1} functions validated: {2}", Errors, n, string.Join(", ", failed_api)); }
// we just want to confirm the symbol exists so `dlsym` can be disabled protected void Check(Assembly a) { Errors = 0; ErrorData.Clear(); int n = 0; foreach (var t in a.GetTypes()) { foreach (var m in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) { continue; } var dllimport = m.GetCustomAttribute <DllImportAttribute> (); string name = dllimport.EntryPoint ?? m.Name; switch (name) { // known not to be present in ARM64 case "objc_msgSend_stret": case "objc_msgSendSuper_stret": // the linker normally removes them (IntPtr.Size optimization) continue; } string path = dllimport.Value; switch (path) { case "__Internal": // load from executable path = null; break; #if NET case "QCall": // Globalization hasn't been implemented yet: https://github.com/xamarin/xamarin-macios/issues/8906 if (name.StartsWith("GlobalizationNative_", StringComparison.Ordinal)) { continue; } break; case "libhostpolicy": // There's no libhostpolicy library. // https://github.com/dotnet/runtime/issues/38543 continue; case "libSystem.Native": path += ".dylib"; break; #endif case "libc": // we still have some rogue/not-fully-qualified DllImport path = "/usr/lib/libSystem.dylib"; break; case "System.Native": case "System.Security.Cryptography.Native.Apple": case "System.Net.Security.Native": if (MonoNativeConfig.LinkMode == MonoNativeLinkMode.None) { continue; } #if __IOS__ path = MonoNativeConfig.GetPInvokeLibraryName(MonoNativeFlavor.Compat, MonoNativeConfig.LinkMode); #else path = null; #endif break; } var lib = Dlfcn.dlopen(path, 0); var h = Dlfcn.dlsym(lib, name); if (h == IntPtr.Zero) { ReportError("Could not find the symbol '{0}' in {1}", name, path); } Dlfcn.dlclose(lib); n++; } } Assert.AreEqual(0, Errors, "{0} errors found in {1} symbol lookups{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
// we just want to confirm the symbol exists so `dlsym` can be disabled protected void Check(Assembly a) { Errors = 0; ErrorData.Clear(); int n = 0; foreach (var t in a.GetTypes()) { foreach (var m in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) { continue; } var dllimport = m.GetCustomAttribute <DllImportAttribute> (); string name = dllimport.EntryPoint ?? m.Name; switch (name) { // known not to be present in ARM64 case "objc_msgSend_stret": case "objc_msgSendSuper_stret": // the linker normally removes them (IntPtr.Size optimization) continue; } string path = dllimport.Value; switch (path) { case "__Internal": // load from executable path = null; break; #if NET case "libSystem.Globalization.Native": // load from executable (like __Internal above since it's part of the static library) path = null; break; case "libSystem.Native": path += ".dylib"; break; #endif case "libc": // we still have some rogue/not-fully-qualified DllImport path = "/usr/lib/libSystem.dylib"; break; case "System.Native": case "System.Security.Cryptography.Native.Apple": case "System.Net.Security.Native": if (MonoNativeConfig.LinkMode == MonoNativeLinkMode.None) { continue; } #if __IOS__ path = MonoNativeConfig.GetPInvokeLibraryName(MonoNativeFlavor.Compat, MonoNativeConfig.LinkMode); #else path = null; #endif break; } var lib = Dlfcn.dlopen(path, 0); var h = Dlfcn.dlsym(lib, name); if (h == IntPtr.Zero) { ReportError("Could not find the symbol '{0}' in {1} for the P/Invoke {2}.{3} in {4}", name, path, t.FullName, m.Name, a.GetName().Name); } else if (path != null) { // Verify that the P/Invoke points to the right library. Dl_info info = default(Dl_info); var found = dladdr(h, out info); if (found != 0) { // Resolve symlinks in both cases var dllImportPath = ResolveLibrarySymlinks(path); var foundLibrary = ResolveLibrarySymlinks(Marshal.PtrToStringAuto(info.dli_fname)); if (Skip(name, ref dllImportPath, ref foundLibrary)) { // Skipped } else if (foundLibrary != dllImportPath) { ReportError($"Found the symbol '{name}' in the library '{foundLibrary}', but the P/Invoke {t.FullName}.{m.Name} in {a.GetName ().Name} claims it's in '{dllimport.Value}'."); } } else { Console.WriteLine($"Unable to find the library for the symbol '{name}' claimed to be in {path} for the P/Invoke {t.FullName}.{m.Name} in {a.GetName ().Name} (rv: {found})"); } } Dlfcn.dlclose(lib); n++; } } Assert.AreEqual(0, Errors, "{0} errors found in {1} symbol lookups{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }