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).
{
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;
*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());
#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)
{
}
// IDebugClient
//----------------------------------------------------------------------------
+PCSTR
+DebugClient::GetCoreClrDirectory()
+{
+ return m_coreclrDirectory;
+}
+
DWORD_PTR
DebugClient::GetExpression(
PCSTR exp)
private:
lldb::SBDebugger &m_debugger;
lldb::SBCommandReturnObject &m_returnObject;
+ char *m_coreclrDirectory;
void OutputString(ULONG mask, PCSTR str);
lldb::SBProcess GetCurrentProcess();
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();
//----------------------------------------------------------------------------
// IDebugClient
//----------------------------------------------------------------------------
+ PCSTR GetCoreClrDirectory();
+
DWORD_PTR GetExpression(
PCSTR exp);
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;
};
#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
class sosCommand : public lldb::SBCommandPluginInterface
{
void *m_sosHandle;
+ char m_coreclrDirectory[MAX_PATH];
public:
sosCommand()
char** arguments,
lldb::SBCommandReturnObject &result)
{
- DebugClient* client = new DebugClient(debugger, result);
+ DebugClient* client = new DebugClient(debugger, result, m_coreclrDirectory);
if (arguments)
{
LoadSos(client);
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
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
OpenMutexW
OpenSemaphoreW
PAL_Random
+PAL_RegisterModule
+PAL_UnregisterModule
QueryPerformanceCounter
QueryPerformanceFrequency
RaiseException
void);
PALIMPORT
+HINSTANCE
+PALAPI
+PAL_RegisterModule(
+ IN LPCSTR lpLibFileName);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_UnregisterModule(
+ IN HINSTANCE hInstance);
+
+PALIMPORT
HMODULE
PALAPI
PAL_RegisterLibraryW(
#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 */
// 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);
/*++
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
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");
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
// 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_
module->refcount = 1;
#endif // NEED_DLCOMPAT
module->self = module;
+ module->hinstance = NULL;
module->ThreadLibCalls = TRUE;
module->next = NULL;
module->prev = NULL;
/* 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... */
// 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_
// 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)
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