summaryrefslogtreecommitdiff
path: root/src/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp')
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp
new file mode 100644
index 0000000000..1a6d73da0a
--- /dev/null
+++ b/src/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp
@@ -0,0 +1,309 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+//----------------------------------------------------------
+// SuperPMI-Shim-Collector.cpp - Shim that collects and yields .mc (method context) files.
+//----------------------------------------------------------
+
+#include "standardpch.h"
+#include "coreclrcallbacks.h"
+#include "icorjitcompiler.h"
+#include "runtimedetails.h"
+#include "errorhandling.h"
+#include "logging.h"
+#include "spmiutil.h"
+#include "jithost.h"
+
+//Assumptions:
+// -We'll never be unloaded - we leak memory and have no facility to unload libraries
+// -printf output to console is okay
+
+HMODULE g_hRealJit = 0; //We leak this currently (could do the proper shutdown in process_detach)
+WCHAR* g_realJitPath = nullptr; //We leak this (could do the proper shutdown in process_detach)
+WCHAR* g_logPath = nullptr; //Again, we leak this one too...
+WCHAR* g_dataFileName = nullptr; //We leak this
+char* g_logFilePath = nullptr; //We *don't* leak this, hooray!
+WCHAR* g_HomeDirectory = nullptr;
+WCHAR* g_DefaultRealJitPath = nullptr;
+MethodContext* g_globalContext = nullptr;
+
+void SetDefaultPaths()
+{
+ if (g_HomeDirectory == nullptr)
+ {
+ g_HomeDirectory = GetEnvironmentVariableWithDefaultW(W("HOME"), W("."));
+ }
+
+ if (g_DefaultRealJitPath == nullptr)
+ {
+ size_t len = wcslen(g_HomeDirectory) + 1 + wcslen(DEFAULT_REAL_JIT_NAME_W) + 1;
+ g_DefaultRealJitPath = new WCHAR[len];
+ wcscpy_s(g_DefaultRealJitPath, len, g_HomeDirectory);
+ wcscat_s(g_DefaultRealJitPath, len, DIRECTORY_SEPARATOR_STR_W);
+ wcscat_s(g_DefaultRealJitPath, len, DEFAULT_REAL_JIT_NAME_W);
+ }
+}
+
+void SetLibName()
+{
+ if (g_realJitPath == nullptr)
+ {
+ g_realJitPath = GetEnvironmentVariableWithDefaultW(W("SuperPMIShimPath"), g_DefaultRealJitPath);
+ }
+}
+
+void SetLogPath()
+{
+ if (g_logPath == nullptr)
+ {
+ g_logPath = GetEnvironmentVariableWithDefaultW(W("SuperPMIShimLogPath"), g_HomeDirectory);
+ }
+}
+
+void SetLogPathName()
+{
+ // NOTE: under PAL, we don't get the comand line, so we depend on the random number generator to give us a unique filename.
+ WCHAR *OriginalExecutableName = GetCommandLineW();//TODO-Cleanup: not cool to write to the process view of commandline....
+ size_t len = wcslen(OriginalExecutableName);
+ WCHAR *ExecutableName = new WCHAR[len+1];
+ wcscpy_s(ExecutableName, len+1, OriginalExecutableName);
+ ExecutableName[len] = W('\0');
+ WCHAR *quote1 = NULL;
+
+ //if there are any quotes in filename convert them to spaces.
+ while ((quote1 = wcsstr(ExecutableName, W("\""))) != NULL)
+ *quote1 = W(' ');
+
+ //remove any illegal or annoying characters from file name by converting them to underscores
+ while ((quote1 = wcspbrk(ExecutableName, W("=<>:\"/\\|?! *.,"))) != NULL)
+ *quote1 = W('_');
+
+ const WCHAR *DataFileExtension = W(".mc");
+ size_t ExecutableNameLength = wcslen(ExecutableName);
+ size_t DataFileExtensionLength = wcslen(DataFileExtension);
+ size_t logPathLength = wcslen(g_logPath);
+
+ size_t dataFileNameLength = logPathLength + 1 + ExecutableNameLength + 1 + DataFileExtensionLength + 1;
+
+ const size_t MaxAcceptablePathLength = MAX_PATH - 20; // subtract 20 to leave buffer, for possible random number addition
+ if (dataFileNameLength >= MaxAcceptablePathLength)
+ {
+ // The path name is too long; creating the file will fail. This can happen because we use the command line,
+ // which for ngen includes lots of environment variables, for example.
+
+ // Assume (!) the extra space is all in the ExecutableName, so shorten that.
+ ExecutableNameLength -= dataFileNameLength - MaxAcceptablePathLength;
+
+ dataFileNameLength = MaxAcceptablePathLength;
+ }
+
+ // Always add a random number, just in case the above doesn't give us a unique filename.
+#ifdef FEATURE_PAL
+ unsigned __int64 randNumber = 0;
+ const size_t RandNumberLength = sizeof(randNumber) * 2 + 1; // 16 hex digits + null
+ WCHAR RandNumberString[RandNumberLength];
+ PAL_Random(/* bStrong */ FALSE, &randNumber, sizeof(randNumber));
+ swprintf_s(RandNumberString, RandNumberLength, W("%016llX"), randNumber);
+#else // !FEATURE_PAL
+ unsigned int randNumber = 0;
+ const size_t RandNumberLength = sizeof(randNumber) * 2 + 1; // 8 hex digits + null
+ WCHAR RandNumberString[RandNumberLength];
+ rand_s(&randNumber);
+ swprintf_s(RandNumberString, RandNumberLength, W("%08X"), randNumber);
+#endif // !FEATURE_PAL
+
+ dataFileNameLength += RandNumberLength - 1;
+
+ // Construct the full pathname we're going to use.
+ g_dataFileName = new WCHAR[dataFileNameLength];
+ g_dataFileName[0] = 0;
+ wcsncat_s(g_dataFileName, dataFileNameLength, g_logPath, logPathLength);
+ wcsncat_s(g_dataFileName, dataFileNameLength, DIRECTORY_SEPARATOR_STR_W, 1);
+ wcsncat_s(g_dataFileName, dataFileNameLength, ExecutableName, ExecutableNameLength);
+
+ if (RandNumberLength > 0)
+ {
+ wcsncat_s(g_dataFileName, dataFileNameLength, RandNumberString, RandNumberLength);
+ }
+
+ wcsncat_s(g_dataFileName, dataFileNameLength, DataFileExtension, DataFileExtensionLength);
+}
+
+// TODO: this only works for ANSI file paths...
+void SetLogFilePath()
+{
+ if (g_logFilePath == nullptr)
+ {
+ // If the environment variable isn't set, we don't enable file logging
+ g_logFilePath = GetEnvironmentVariableWithDefaultA("SuperPMIShimLogFilePath", nullptr);
+ }
+}
+
+extern "C"
+BOOL
+#ifndef FEATURE_PAL
+APIENTRY
+#endif // !FEATURE_PAL
+DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+#ifdef FEATURE_PAL
+ if (0 != PAL_InitializeDLL())
+ {
+ fprintf(stderr, "Error: Fail to PAL_InitializeDLL\n");
+ exit(1);
+ }
+#endif // FEATURE_PAL
+
+ Logger::Initialize();
+ SetLogFilePath();
+ Logger::OpenLogFile(g_logFilePath);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ Logger::Shutdown();
+
+ delete[] g_logFilePath;
+ g_logFilePath = nullptr;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+// Exported via def file
+extern "C"
+void __stdcall jitStartup(ICorJitHost* host)
+{
+ SetDefaultPaths();
+ SetLibName();
+
+ //Load Library
+ if (g_hRealJit == 0)
+ {
+ g_hRealJit = ::LoadLibraryW(g_realJitPath);
+ if (g_hRealJit == 0)
+ {
+ LogError("jitStartup() - LoadLibrary failed to load '%ws' (0x%08x)", g_realJitPath, ::GetLastError());
+ return;
+ }
+ }
+
+ // Get the required entrypoint
+ PjitStartup pnjitStartup = (PjitStartup)::GetProcAddress(g_hRealJit, "jitStartup");
+ if (pnjitStartup == nullptr)
+ {
+ // This portion of the interface is not used by the JIT under test.
+ return;
+ }
+
+ g_globalContext = new MethodContext();
+ g_ourJitHost = new JitHost(host, g_globalContext);
+ pnjitStartup(g_ourJitHost);
+}
+
+//Exported via def file
+extern "C"
+ICorJitCompiler* __stdcall getJit()
+{
+ DWORD dwRetVal = 0;
+ PgetJit pngetJit;
+ interceptor_ICJC *pJitInstance = nullptr;
+ ICorJitCompiler *tICJI = nullptr;
+
+ SetDefaultPaths();
+ SetLibName();
+ SetLogPath();
+ SetLogPathName();
+
+ //Load Library
+ if(g_hRealJit == 0)
+ {
+ g_hRealJit = ::LoadLibraryW(g_realJitPath);
+ if(g_hRealJit == 0)
+ {
+ LogError("getJit() - LoadLibrary failed to load '%ws' (0x%08x)", g_realJitPath, ::GetLastError());
+ return nullptr;
+ }
+ }
+
+ //get the required entrypoints
+ pngetJit = (PgetJit)::GetProcAddress(g_hRealJit, "getJit");
+ if(pngetJit == 0)
+ {
+ LogError("getJit() - GetProcAddress 'getJit' failed (0x%08x)", ::GetLastError());
+ return nullptr;
+ }
+
+ tICJI = pngetJit();
+ if(tICJI == nullptr)
+ {
+ LogError("getJit() - pngetJit gave us null");
+ return nullptr;
+ }
+
+ pJitInstance = new interceptor_ICJC();
+ pJitInstance->original_ICorJitCompiler = tICJI;
+
+ //create our datafile
+ pJitInstance->hFile = CreateFileW(g_dataFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (pJitInstance->hFile == INVALID_HANDLE_VALUE)
+ {
+ LogError("Couldn't open file '%ws': error %d", g_dataFileName, GetLastError());
+ }
+
+ return pJitInstance;
+}
+
+//Exported via def file
+extern "C"
+void __stdcall sxsJitStartup(CoreClrCallbacks const & original_cccallbacks)
+{
+ PsxsJitStartup pnsxsJitStartup;
+
+ SetDefaultPaths();
+ SetLibName();
+
+ //Load Library
+ if(g_hRealJit == 0)
+ {
+ g_hRealJit = ::LoadLibraryW(g_realJitPath);
+ if(g_hRealJit == 0)
+ {
+ LogError("sxsJitStartup() - LoadLibrary failed to load '%ws' (0x%08x)", g_realJitPath, ::GetLastError());
+ return;
+ }
+ }
+
+ //get entry point
+ pnsxsJitStartup = (PsxsJitStartup)::GetProcAddress(g_hRealJit, "sxsJitStartup");
+ if(pnsxsJitStartup == 0)
+ {
+ LogError("sxsJitStartup() - GetProcAddress 'sxsJitStartup' failed (0x%08x)", ::GetLastError());
+ return;
+ }
+
+ //Setup CoreClrCallbacks and call sxsJitStartup
+ original_CoreClrCallbacks = new CoreClrCallbacks();
+ original_CoreClrCallbacks->m_hmodCoreCLR = original_cccallbacks.m_hmodCoreCLR;
+ original_CoreClrCallbacks->m_pfnIEE = original_cccallbacks.m_pfnIEE;
+ original_CoreClrCallbacks->m_pfnGetCORSystemDirectory = original_cccallbacks.m_pfnGetCORSystemDirectory;
+ original_CoreClrCallbacks->m_pfnGetCLRFunction = original_cccallbacks.m_pfnGetCLRFunction;
+
+ CoreClrCallbacks *temp = new CoreClrCallbacks();
+
+ temp->m_hmodCoreCLR = original_cccallbacks.m_hmodCoreCLR;
+ temp->m_pfnIEE = IEE_t;
+ temp->m_pfnGetCORSystemDirectory = original_cccallbacks.m_pfnGetCORSystemDirectory;
+ temp->m_pfnGetCLRFunction = GetCLRFunction;
+
+ pnsxsJitStartup(*temp);
+}