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);
}