1//
2// Copyright (c) Microsoft. All rights reserved.
3// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4//
5
6//----------------------------------------------------------
7// SuperPMI-Shim-Collector.cpp - Shim that collects and yields .mc (method context) files.
8//----------------------------------------------------------
9
10#include "standardpch.h"
11#include "coreclrcallbacks.h"
12#include "icorjitcompiler.h"
13#include "runtimedetails.h"
14#include "errorhandling.h"
15#include "logging.h"
16#include "spmiutil.h"
17#include "jithost.h"
18
19// Assumptions:
20// -We'll never be unloaded - we leak memory and have no facility to unload libraries
21// -printf output to console is okay
22
23HMODULE g_hRealJit = 0; // We leak this currently (could do the proper shutdown in process_detach)
24WCHAR* g_realJitPath = nullptr; // We leak this (could do the proper shutdown in process_detach)
25WCHAR* g_logPath = nullptr; // Again, we leak this one too...
26WCHAR* g_dataFileName = nullptr; // We leak this
27char* g_logFilePath = nullptr; // We *don't* leak this, hooray!
28WCHAR* g_HomeDirectory = nullptr;
29WCHAR* g_DefaultRealJitPath = nullptr;
30MethodContext* g_globalContext = nullptr;
31
32void SetDefaultPaths()
33{
34 if (g_HomeDirectory == nullptr)
35 {
36 g_HomeDirectory = GetEnvironmentVariableWithDefaultW(W("HOME"), W("."));
37 }
38
39 if (g_DefaultRealJitPath == nullptr)
40 {
41 size_t len = wcslen(g_HomeDirectory) + 1 + wcslen(DEFAULT_REAL_JIT_NAME_W) + 1;
42 g_DefaultRealJitPath = new WCHAR[len];
43 wcscpy_s(g_DefaultRealJitPath, len, g_HomeDirectory);
44 wcscat_s(g_DefaultRealJitPath, len, DIRECTORY_SEPARATOR_STR_W);
45 wcscat_s(g_DefaultRealJitPath, len, DEFAULT_REAL_JIT_NAME_W);
46 }
47}
48
49void SetLibName()
50{
51 if (g_realJitPath == nullptr)
52 {
53 g_realJitPath = GetEnvironmentVariableWithDefaultW(W("SuperPMIShimPath"), g_DefaultRealJitPath);
54 }
55}
56
57void SetLogPath()
58{
59 if (g_logPath == nullptr)
60 {
61 g_logPath = GetEnvironmentVariableWithDefaultW(W("SuperPMIShimLogPath"), g_HomeDirectory);
62 }
63}
64
65void SetLogPathName()
66{
67 // NOTE: under PAL, we don't get the command line, so we depend on the random number generator to give us a unique
68 // filename.
69 const WCHAR* originalExecutableName = GetCommandLineW();
70 size_t executableNameLength = wcslen(originalExecutableName);
71 WCHAR* executableName = new WCHAR[executableNameLength + 1];
72 wcscpy_s(executableName, executableNameLength + 1, originalExecutableName);
73 executableName[executableNameLength] = W('\0');
74
75 const WCHAR* DataFileExtension = W(".mc");
76 g_dataFileName = getResultFileName(g_logPath, executableName, DataFileExtension);
77}
78
79// TODO: this only works for ANSI file paths...
80void SetLogFilePath()
81{
82 if (g_logFilePath == nullptr)
83 {
84 // If the environment variable isn't set, we don't enable file logging
85 g_logFilePath = GetEnvironmentVariableWithDefaultA("SuperPMIShimLogFilePath", nullptr);
86 }
87}
88
89extern "C" BOOL
90#ifndef FEATURE_PAL
91 APIENTRY
92#endif // !FEATURE_PAL
93 DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
94{
95 switch (ul_reason_for_call)
96 {
97 case DLL_PROCESS_ATTACH:
98#ifdef FEATURE_PAL
99 if (0 != PAL_InitializeDLL())
100 {
101 fprintf(stderr, "Error: Fail to PAL_InitializeDLL\n");
102 exit(1);
103 }
104#endif // FEATURE_PAL
105
106 Logger::Initialize();
107 SetLogFilePath();
108 Logger::OpenLogFile(g_logFilePath);
109 break;
110
111 case DLL_PROCESS_DETACH:
112 Logger::Shutdown();
113
114 delete[] g_logFilePath;
115 g_logFilePath = nullptr;
116
117 break;
118
119 case DLL_THREAD_ATTACH:
120 case DLL_THREAD_DETACH:
121 break;
122 }
123 return TRUE;
124}
125
126// Exported via def file
127extern "C" void __stdcall jitStartup(ICorJitHost* host)
128{
129 SetDefaultPaths();
130 SetLibName();
131
132 if (!LoadRealJitLib(g_hRealJit, g_realJitPath))
133 {
134 return;
135 }
136
137 // Get the required entrypoint
138 PjitStartup pnjitStartup = (PjitStartup)::GetProcAddress(g_hRealJit, "jitStartup");
139 if (pnjitStartup == nullptr)
140 {
141 // This portion of the interface is not used by the JIT under test.
142 return;
143 }
144
145 g_globalContext = new MethodContext();
146 g_ourJitHost = new JitHost(host, g_globalContext);
147 pnjitStartup(g_ourJitHost);
148}
149
150// Exported via def file
151extern "C" ICorJitCompiler* __stdcall getJit()
152{
153 DWORD dwRetVal = 0;
154 PgetJit pngetJit;
155 interceptor_ICJC* pJitInstance = nullptr;
156 ICorJitCompiler* tICJI = nullptr;
157
158 SetDefaultPaths();
159 SetLibName();
160 SetLogPath();
161 SetLogPathName();
162
163 if (!LoadRealJitLib(g_hRealJit, g_realJitPath))
164 {
165 return nullptr;
166 }
167
168 // get the required entrypoints
169 pngetJit = (PgetJit)::GetProcAddress(g_hRealJit, "getJit");
170 if (pngetJit == 0)
171 {
172 LogError("getJit() - GetProcAddress 'getJit' failed (0x%08x)", ::GetLastError());
173 return nullptr;
174 }
175
176 tICJI = pngetJit();
177 if (tICJI == nullptr)
178 {
179 LogError("getJit() - pngetJit gave us null");
180 return nullptr;
181 }
182
183 pJitInstance = new interceptor_ICJC();
184 pJitInstance->original_ICorJitCompiler = tICJI;
185
186 // create our datafile
187 pJitInstance->hFile = CreateFileW(g_dataFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
188 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
189 if (pJitInstance->hFile == INVALID_HANDLE_VALUE)
190 {
191 LogError("Couldn't open file '%ws': error %d", g_dataFileName, GetLastError());
192 }
193
194 return pJitInstance;
195}
196
197// Exported via def file
198extern "C" void __stdcall sxsJitStartup(CoreClrCallbacks const& original_cccallbacks)
199{
200 PsxsJitStartup pnsxsJitStartup;
201
202 SetDefaultPaths();
203 SetLibName();
204
205 if (!LoadRealJitLib(g_hRealJit, g_realJitPath))
206 {
207 return;
208 }
209
210 // get entry point
211 pnsxsJitStartup = (PsxsJitStartup)::GetProcAddress(g_hRealJit, "sxsJitStartup");
212 if (pnsxsJitStartup == 0)
213 {
214 LogError("sxsJitStartup() - GetProcAddress 'sxsJitStartup' failed (0x%08x)", ::GetLastError());
215 return;
216 }
217
218 // Setup CoreClrCallbacks and call sxsJitStartup
219 original_CoreClrCallbacks = new CoreClrCallbacks();
220 original_CoreClrCallbacks->m_hmodCoreCLR = original_cccallbacks.m_hmodCoreCLR;
221 original_CoreClrCallbacks->m_pfnIEE = original_cccallbacks.m_pfnIEE;
222 original_CoreClrCallbacks->m_pfnGetCORSystemDirectory = original_cccallbacks.m_pfnGetCORSystemDirectory;
223 original_CoreClrCallbacks->m_pfnGetCLRFunction = original_cccallbacks.m_pfnGetCLRFunction;
224
225 CoreClrCallbacks* temp = new CoreClrCallbacks();
226
227 temp->m_hmodCoreCLR = original_cccallbacks.m_hmodCoreCLR;
228 temp->m_pfnIEE = IEE_t;
229 temp->m_pfnGetCORSystemDirectory = original_cccallbacks.m_pfnGetCORSystemDirectory;
230 temp->m_pfnGetCLRFunction = GetCLRFunction;
231
232 pnsxsJitStartup(*temp);
233}
234