Remove the dependency on LD_LIBRARY_PATH in the sos code (issue #820). Uses the corec...
authorMike McLaughlin <mikem@microsoft.com>
Mon, 8 Jun 2015 21:50:40 +0000 (14:50 -0700)
committerMike McLaughlin <mikem@microsoft.com>
Tue, 9 Jun 2015 22:08:19 +0000 (15:08 -0700)
Preload the DAC module in the lldb sos plugin so SOS and DBI can still use DAC's PAL.

Fix the HMODULE handle passed to DLLMain to be a handle in the target module's PAL context (issue #931).

src/ToolBox/SOS/Strike/util.cpp
src/ToolBox/SOS/lldbplugin/debugclient.cpp
src/ToolBox/SOS/lldbplugin/debugclient.h
src/ToolBox/SOS/lldbplugin/inc/dbgeng.h
src/ToolBox/SOS/lldbplugin/mstypes.h
src/ToolBox/SOS/lldbplugin/soscommand.cpp
src/dlls/mscoree/mscorwks_unixexports.src
src/pal/inc/pal.h
src/pal/src/include/pal/module.h
src/pal/src/loader/module.cpp

index c190ee7..361ab45 100644 (file)
@@ -4141,8 +4141,11 @@ HRESULT LoadClrDebugDll(void)
         {
             return E_FAIL;
         }
-        // Assumes that LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH on OSx) is set to runtime binaries path
-        HMODULE hdac = LoadLibraryA(MAKEDLLNAME_A("mscordaccore"));
+        char dacModulePath[MAX_PATH];
+        strcpy_s(dacModulePath, _countof(dacModulePath), g_ExtClient->GetCoreClrDirectory());
+        strcat_s(dacModulePath, _countof(dacModulePath), MAKEDLLNAME_A("mscordaccore"));
+
+        HMODULE hdac = LoadLibraryA(dacModulePath);
         if (hdac == NULL)
         {
             return E_FAIL;
@@ -4419,8 +4422,16 @@ public:
         *phModule = callbackData.hModule;
         return hr;
 #else
-        // Assumes that LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH on OSx) is set to runtime binaries path. Ignore the version info for now.
-        *phModule = LoadLibraryW(pwszFileName);
+        WCHAR modulePath[MAX_PATH];
+        int length = MultiByteToWideChar(CP_ACP, 0, g_ExtClient->GetCoreClrDirectory(), -1, modulePath, _countof(modulePath));
+        if (0 >= length)
+        {
+            ExtOut("MultiByteToWideChar(coreclrDirectory) failed. Last error = 0x%x\n", GetLastError());
+            return E_FAIL;
+        }
+        wcscat_s(modulePath, _countof(modulePath), pwszFileName);
+
+        *phModule = LoadLibraryW(modulePath);
         if (*phModule == NULL)
         {
             HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
index 2d892e3..8b2f9c7 100644 (file)
 #include <dbgtargetcontext.h>
 #include <string>
 
-DebugClient::DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject) :
+DebugClient::DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, char *coreclrDirectory) :
     m_debugger(debugger),
-    m_returnObject(returnObject)
+    m_returnObject(returnObject),
+    m_coreclrDirectory(coreclrDirectory)
 {
 }
 
@@ -860,6 +861,12 @@ DebugClient::GetFrameOffset(
 // IDebugClient
 //----------------------------------------------------------------------------
 
+PCSTR
+DebugClient::GetCoreClrDirectory()
+{
+    return m_coreclrDirectory;
+}
+
 DWORD_PTR
 DebugClient::GetExpression(
     PCSTR exp)
index dda2f81..d2a2201 100644 (file)
@@ -8,6 +8,7 @@ class DebugClient : public IDebugClient
 private:
     lldb::SBDebugger &m_debugger;
     lldb::SBCommandReturnObject &m_returnObject;
+    char *m_coreclrDirectory;
 
     void OutputString(ULONG mask, PCSTR str);
     lldb::SBProcess GetCurrentProcess();
@@ -18,7 +19,7 @@ private:
     DWORD_PTR GetRegister(lldb::SBFrame frame, const char *name);
 
 public:
-    DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject);
+    DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, char *coreclrDirectory);
     ~DebugClient();
 
     //----------------------------------------------------------------------------
@@ -166,6 +167,8 @@ public:
     // IDebugClient
     //----------------------------------------------------------------------------
 
+    PCSTR GetCoreClrDirectory();
+
     DWORD_PTR GetExpression(
         PCSTR exp);
 
index 41d929f..9871a3e 100644 (file)
@@ -347,6 +347,11 @@ typedef class IDebugRegister* PDEBUG_REGISTERS;
 class IDebugClient : IDebugControl2, IDebugDataSpaces, IDebugSymbols, IDebugSystemObjects, IDebugRegister
 {
 public:
+    // Returns the coreclr module directory found by lldb plugin 
+    // in the target process.
+    virtual PCSTR GetCoreClrDirectory() = 0;
+
+    // Evaluates a lldb expression into a value.
     virtual DWORD_PTR GetExpression(
         /* [in] */ PCSTR exp) = 0;
 };
index 338fcb7..17d421e 100644 (file)
@@ -51,6 +51,8 @@ typedef int HRESULT;
 #define E_NOTIMPL                        (HRESULT)0x80004001
 #define E_FAIL                           (HRESULT)0x80004005
 
+#define MAX_PATH                         260 
+
 #if defined(_MSC_VER) || defined(__llvm__)
 #define DECLSPEC_ALIGN(x)   __declspec(align(x))
 #else
index b13b69c..b321321 100644 (file)
@@ -10,6 +10,7 @@
 class sosCommand : public lldb::SBCommandPluginInterface
 {
     void *m_sosHandle;
+    char m_coreclrDirectory[MAX_PATH];
 
 public:
     sosCommand()
@@ -22,7 +23,7 @@ public:
                char** arguments,
                lldb::SBCommandReturnObject &result)
     {
-        DebugClient* client = new DebugClient(debugger, result);
+        DebugClient* client = new DebugClient(debugger, result, m_coreclrDirectory);
         if (arguments)
         {
             LoadSos(client);
@@ -44,7 +45,7 @@ public:
                     HRESULT hr = commandFunc(client, sosArgs);
                     if (hr != S_OK)
                     {
-                        client->Output(DEBUG_OUTPUT_ERROR, "%s %s failed", sosCommand, sosArgs);
+                        client->Output(DEBUG_OUTPUT_ERROR, "%s %s failed\n", sosCommand, sosArgs);
                     }
                 }
                 else
@@ -67,23 +68,38 @@ public:
             const char *directory = client->GetModuleDirectory(coreclrModule);
             if (directory == NULL)
             {
-                client->Output(DEBUG_OUTPUT_WARNING, "The %s module is not loaded yet in the target process.\n", coreclrModule);
+                client->Output(DEBUG_OUTPUT_WARNING, "The %s module is not loaded yet in the target process\n", coreclrModule);
             }
             else 
             {
-                std::string sosLibrary;
-                sosLibrary.append(directory);
-                sosLibrary.append("/");
-                sosLibrary.append(MAKEDLLNAME_A("sos"));
+                std::string directoryString;
+                directoryString.append(directory);
+                directoryString.append("/");
+                directoryString.copy(m_coreclrDirectory, MAX_PATH, 0);
 
-                m_sosHandle = dlopen(sosLibrary.c_str(), RTLD_NOW);
-                if (m_sosHandle == NULL)
-                {
-                    client->Output(DEBUG_OUTPUT_ERROR, "dlopen(%s) failed %s.\n", sosLibrary.c_str(), dlerror());
-                }
+                // Load the DAC module first explicitly because SOS and DBI
+                // have implicit references to the DAC's PAL.
+                LoadModule(client, MAKEDLLNAME_A("mscordaccore"));
+
+                m_sosHandle = LoadModule(client, MAKEDLLNAME_A("sos"));
             }
         }
     }
+
+    void *
+    LoadModule(DebugClient *client, const char *moduleName)
+    {
+        std::string modulePath(m_coreclrDirectory);
+        modulePath.append(moduleName);
+
+        void *moduleHandle = dlopen(modulePath.c_str(), RTLD_NOW);
+        if (moduleHandle == NULL)
+        {
+            client->Output(DEBUG_OUTPUT_ERROR, "dlopen(%s) failed %s\n", modulePath.c_str(), dlerror());
+        }
+
+        return moduleHandle;
+    }
 };
 
 bool
index c137a97..be6018f 100644 (file)
@@ -53,6 +53,8 @@ OpenEventW
 OpenMutexW
 OpenSemaphoreW
 PAL_Random
+PAL_RegisterModule
+PAL_UnregisterModule
 QueryPerformanceCounter  
 QueryPerformanceFrequency
 RaiseException
index da72c91..69b5362 100644 (file)
@@ -515,6 +515,18 @@ PAL_InitializeDebug(
     void);
 
 PALIMPORT
+HINSTANCE
+PALAPI
+PAL_RegisterModule(
+    IN LPCSTR lpLibFileName);
+
+PALIMPORT
+VOID 
+PALAPI
+PAL_UnregisterModule(
+    IN HINSTANCE hInstance);
+
+PALIMPORT
 HMODULE
 PALAPI
 PAL_RegisterLibraryW(
index 803ca36..a58a82a 100644 (file)
@@ -56,12 +56,15 @@ extern "C"
 #define PAL_SHLIB_SUFFIX ".so"
 #endif
 
-typedef BOOL (__stdcall *PDLLMAIN)(HINSTANCE,DWORD,LPVOID); /* entry point of module */
+typedef BOOL (__stdcall *PDLLMAIN)(HINSTANCE, DWORD, LPVOID);   /* entry point of module */
+typedef HINSTANCE (PALAPI *PREGISTER_MODULE)(LPCSTR);           /* used to create the HINSTANCE for above DLLMain entry point */
+typedef VOID (PALAPI *PUNREGISTER_MODULE)(HINSTANCE);           /* used to cleanup the HINSTANCE for above DLLMain entry point */
 
 typedef struct _MODSTRUCT
 {
     HMODULE self;         /* circular reference to this module */
     void *dl_handle;      /* handle returned by dlopen() */
+    HINSTANCE hinstance;  /* handle returned by PAL_RegisterLibrary */
 #if defined(CORECLR) && defined(__APPLE__)
     CORECLRHANDLE sys_module; /* System modules can be loaded via mechanisms other than dlopen() under
                                * CoreCLR/Mac */
index a0aad2b..aadf128 100644 (file)
@@ -480,9 +480,17 @@ FreeLibrary(
             // This module may be foreign to our PAL, so leave our PAL.
             // If it depends on us, it will re-enter.
             PAL_LeaveHolder holder;
-            module->pDllMain((HMODULE)module, DLL_PROCESS_DETACH, NULL);
+            module->pDllMain(module->hinstance, DLL_PROCESS_DETACH, NULL);
         }
 
+        if (module->hinstance)
+        {
+            PUNREGISTER_MODULE unregisterModule = (PUNREGISTER_MODULE)dlsym(module->dl_handle, "PAL_UnregisterModule");
+            if (unregisterModule)
+            {
+                 unregisterModule(module->hinstance);
+            }
+        }
 /* ...and set nesting level back to what it was */
 #if !_NO_DEBUG_MESSAGES_
         DBG_change_entrylevel(old_level);
@@ -669,6 +677,57 @@ done:
 
 /*++
 Function:
+  PAL_RegisterModule
+
+  Register the module with the target module and return a module handle in
+  the target module's context.
+
+--*/
+
+HINSTANCE
+PALAPI
+PAL_RegisterModule(
+    IN LPCSTR lpLibFileName)
+{
+    HINSTANCE hinstance = NULL;
+
+    int err = PAL_InitializeDLL();
+    if(err == 0)
+    {
+        PERF_ENTRY(PAL_RegisterModule);
+        ENTRY("PAL_RegisterModule(%s)\n", lpLibFileName ? lpLibFileName : "");
+
+        hinstance = (HINSTANCE)LOADLoadLibrary(lpLibFileName, FALSE);
+
+        LOGEXIT("PAL_RegisterModule returns HINSTANCE %p\n", hinstance);
+        PERF_EXIT(PAL_RegisterModule);
+    }
+
+    return hinstance;
+}
+
+/*++
+Function:
+  PAL_UnregisterModule
+
+  Used to cleanup the module HINSTANCE from PAL_RegisterModule.
+--*/
+VOID
+PALAPI
+PAL_UnregisterModule(
+    IN HINSTANCE hInstance)
+{
+    PERF_ENTRY(PAL_UnregisterModule);
+    ENTRY("PAL_UnregisterModule(hInstance=%p)\n", hInstance);
+
+    FreeLibrary(hInstance);
+
+    LOGEXIT("PAL_UnregisterModule returns\n");
+    PERF_EXIT(PAL_UnregisterModule);
+}
+
+/*++
+Function:
   PAL_RegisterLibraryW
 
   Same as LoadLibraryW, but with only the base name of
@@ -896,6 +955,7 @@ BOOL LOADInitializeModules(LPWSTR exe_name)
     exe_module.next = &pal_module;
     exe_module.prev = &pal_module;
     exe_module.pDllMain = NULL;
+    exe_module.hinstance = NULL;
     exe_module.ThreadLibCalls = TRUE;
     
     TRACE("Initializing module for PAL library\n");
@@ -906,6 +966,7 @@ BOOL LOADInitializeModules(LPWSTR exe_name)
     pal_module.next = &exe_module;
     pal_module.prev = &exe_module;
     pal_module.pDllMain = NULL;
+    pal_module.hinstance = NULL;
     pal_module.ThreadLibCalls = TRUE;
 
     // For platforms where we can't trust the handle to be constant, we need to 
@@ -1102,7 +1163,7 @@ void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved)
                     // This module may be foreign to our PAL, so leave our PAL.
                     // If it depends on us, it will re-enter.
                     PAL_LeaveHolder holder;
-                    module->pDllMain((HMODULE) module, dwReason, lpReserved);
+                    module->pDllMain(module->hinstance, dwReason, lpReserved);
                 }
 
 #if !_NO_DEBUG_MESSAGES_
@@ -1309,6 +1370,7 @@ static MODSTRUCT *LOADAllocModule(void *dl_handle, LPCSTR name)
     module->refcount = 1;
 #endif  // NEED_DLCOMPAT
     module->self = module;
+    module->hinstance = NULL;
     module->ThreadLibCalls = TRUE;
     module->next = NULL;
     module->prev = NULL;
@@ -1454,12 +1516,28 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic)
     /* If it did contain a DllMain, call it. */
     if(module->pDllMain)
     {
-        DWORD dllmain_retval;
+        DWORD dllmain_retval = FALSE;
 
         TRACE("Calling DllMain (%p) for module %S\n", 
               module->pDllMain, 
               module->lib_name ? module->lib_name : W16_NULLSTRING);
 
+        if (NULL == module->hinstance)
+        {
+            PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule");
+            if (registerModule)
+            {
+                module->hinstance = registerModule(ShortAsciiName);
+            }
+            else
+            {
+                // If the target module doesn't have the PAL_RegisterModule export, then use this PAL's
+                // module handle assuming that the target module is referencing this PAL's exported 
+                // functions on said handle.
+                module->hinstance = (HINSTANCE)module;
+            }
+        }
+
         {
 #if !_NO_DEBUG_MESSAGES_
             /* reset ENTRY nesting level back to zero while inside the callback... */
@@ -1471,8 +1549,7 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic)
                 // This module may be foreign to our PAL, so leave our PAL.
                 // If it depends on us, it will re-enter.
                 PAL_LeaveHolder holder;
-                dllmain_retval = module->pDllMain((HINSTANCE) module,
-                    DLL_PROCESS_ATTACH, fDynamic ? NULL : (LPVOID)-1);
+                dllmain_retval = module->pDllMain(module->hinstance, DLL_PROCESS_ATTACH, fDynamic ? NULL : (LPVOID)-1);
             }
 
 #if !_NO_DEBUG_MESSAGES_
@@ -1556,7 +1633,7 @@ static void LOAD_SEH_CallDllMain(MODSTRUCT *module, DWORD dwReason, LPVOID lpRes
             // This module may be foreign to our PAL, so leave our PAL.
             // If it depends on us, it will re-enter.
             PAL_LeaveHolder holder;
-            pParam->module->pDllMain((HMODULE)pParam->module, pParam->dwReason, pParam->lpReserved);
+            pParam->module->pDllMain(pParam->module->hinstance, pParam->dwReason, pParam->lpReserved);
         }
     }
     PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -1897,7 +1974,13 @@ BOOL LOADInitCoreCLRModules(
         return FALSE;
     }
     PDLLMAIN pRuntimeDllMain = (PDLLMAIN)dlsym(pal_module.dl_handle, "CoreDllMain");
-    return pRuntimeDllMain((HMODULE)&pal_module, DLL_PROCESS_ATTACH, NULL);
+    if (!pRuntimeDllMain)
+    {
+        ERROR("Can not find the CoreDllMain entry point in %s\n", szCoreCLRPath);
+        return FALSE;
+    }
+    pal_module.hinstance = (HINSTANCE)LOADLoadLibrary(szCoreCLRPath, FALSE);
+    return pRuntimeDllMain(pal_module.hinstance, DLL_PROCESS_ATTACH, NULL);
 }
 
 // Get base address of the module containing a given symbol