diff --git a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs index 7185d68efe9..1786fc2e3f6 100644 --- a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs +++ b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs @@ -51,11 +51,12 @@ namespace Grpc.Core.Internal Logger.Debug("Attempting to load native library \"{0}\"", this.libraryPath); - this.handle = PlatformSpecificLoadLibrary(this.libraryPath); + this.handle = PlatformSpecificLoadLibrary(this.libraryPath, out string loadLibraryErrorDetail); if (this.handle == IntPtr.Zero) { - throw new IOException(string.Format("Error loading native library \"{0}\"", this.libraryPath)); + throw new IOException(string.Format("Error loading native library \"{0}\". {1}", + this.libraryPath, loadLibraryErrorDetail)); } } @@ -129,31 +130,44 @@ namespace Grpc.Core.Internal /// /// Loads library in a platform specific way. /// - private static IntPtr PlatformSpecificLoadLibrary(string libraryPath) + private static IntPtr PlatformSpecificLoadLibrary(string libraryPath, out string errorMsg) { if (PlatformApis.IsWindows) { + // TODO(jtattermusch): populate the error on Windows + errorMsg = null; return Windows.LoadLibrary(libraryPath); } if (PlatformApis.IsLinux) { if (PlatformApis.IsMono) { - return Mono.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(Mono.dlopen, Mono.dlerror, libraryPath, out errorMsg); } if (PlatformApis.IsNetCore) { - return CoreCLR.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(CoreCLR.dlopen, CoreCLR.dlerror, libraryPath, out errorMsg); } - return Linux.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(Linux.dlopen, Linux.dlerror, libraryPath, out errorMsg); } if (PlatformApis.IsMacOSX) { - return MacOSX.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + return LoadLibraryPosix(MacOSX.dlopen, MacOSX.dlerror, libraryPath, out errorMsg); } throw new InvalidOperationException("Unsupported platform."); } + private static IntPtr LoadLibraryPosix(Func dlopenFunc, Func dlerrorFunc, string libraryPath, out string errorMsg) + { + errorMsg = null; + IntPtr ret = dlopenFunc(libraryPath, RTLD_GLOBAL + RTLD_LAZY); + if (ret == IntPtr.Zero) + { + errorMsg = Marshal.PtrToStringAnsi(dlerrorFunc()); + } + return ret; + } + private static string FirstValidLibraryPath(string[] libraryPathAlternatives) { GrpcPreconditions.CheckArgument(libraryPathAlternatives.Length > 0, "libraryPathAlternatives cannot be empty."); @@ -183,6 +197,9 @@ namespace Grpc.Core.Internal [DllImport("libdl.so")] internal static extern IntPtr dlopen(string filename, int flags); + [DllImport("libdl.so")] + internal static extern IntPtr dlerror(); + [DllImport("libdl.so")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); } @@ -192,6 +209,9 @@ namespace Grpc.Core.Internal [DllImport("libSystem.dylib")] internal static extern IntPtr dlopen(string filename, int flags); + [DllImport("libSystem.dylib")] + internal static extern IntPtr dlerror(); + [DllImport("libSystem.dylib")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); } @@ -208,6 +228,9 @@ namespace Grpc.Core.Internal [DllImport("__Internal")] internal static extern IntPtr dlopen(string filename, int flags); + [DllImport("__Internal")] + internal static extern IntPtr dlerror(); + [DllImport("__Internal")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); } @@ -222,6 +245,9 @@ namespace Grpc.Core.Internal [DllImport("libcoreclr.so")] internal static extern IntPtr dlopen(string filename, int flags); + [DllImport("libcoreclr.so")] + internal static extern IntPtr dlerror(); + [DllImport("libcoreclr.so")] internal static extern IntPtr dlsym(IntPtr handle, string symbol); }