1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5
6//*****************************************************************************
7// unixinterface.cpp
8//
9// Implementation for the interface exposed by libcoreclr.so
10//
11
12//*****************************************************************************
13
14#include "stdafx.h"
15#include <utilcode.h>
16#include <corhost.h>
17#include <configuration.h>
18#ifdef FEATURE_GDBJIT
19#include "../../vm/gdbjithelpers.h"
20#endif // FEATURE_GDBJIT
21
22typedef int (STDMETHODCALLTYPE *HostMain)(
23 const int argc,
24 const wchar_t** argv
25 );
26
27#define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS(__FILE__, (expr))
28
29// Holder for const wide strings
30typedef NewArrayHolder<const WCHAR> ConstWStringHolder;
31
32// Holder for array of wide strings
33class ConstWStringArrayHolder : public NewArrayHolder<LPCWSTR>
34{
35 int m_cElements;
36
37public:
38 ConstWStringArrayHolder() :
39 NewArrayHolder<LPCWSTR>(),
40 m_cElements(0)
41 {
42 }
43
44 void Set(LPCWSTR* value, int cElements)
45 {
46 NewArrayHolder<LPCWSTR>::operator=(value);
47 m_cElements = cElements;
48 }
49
50 ~ConstWStringArrayHolder()
51 {
52 for (int i = 0; i < m_cElements; i++)
53 {
54 delete [] this->m_value[i];
55 }
56 }
57};
58
59// Convert 8 bit string to unicode
60static LPCWSTR StringToUnicode(LPCSTR str)
61{
62 int length = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
63 ASSERTE_ALL_BUILDS(length != 0);
64
65 LPWSTR result = new (nothrow) WCHAR[length];
66 ASSERTE_ALL_BUILDS(result != NULL);
67
68 length = MultiByteToWideChar(CP_UTF8, 0, str, -1, result, length);
69 ASSERTE_ALL_BUILDS(length != 0);
70
71 return result;
72}
73
74// Convert 8 bit string array to unicode string array
75static LPCWSTR* StringArrayToUnicode(int argc, LPCSTR* argv)
76{
77 LPCWSTR* argvW = nullptr;
78
79 if (argc > 0)
80 {
81 argvW = new (nothrow) LPCWSTR[argc];
82 ASSERTE_ALL_BUILDS(argvW != 0);
83
84 for (int i = 0; i < argc; i++)
85 {
86 argvW[i] = StringToUnicode(argv[i]);
87 }
88 }
89
90 return argvW;
91}
92
93static void InitializeStartupFlags(STARTUP_FLAGS* startupFlagsRef)
94{
95 STARTUP_FLAGS startupFlags = static_cast<STARTUP_FLAGS>(
96 STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN |
97 STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN);
98
99 if (Configuration::GetKnobBooleanValue(W("System.GC.Concurrent"), CLRConfig::UNSUPPORTED_gcConcurrent))
100 {
101 startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_CONCURRENT_GC);
102 }
103 if (Configuration::GetKnobBooleanValue(W("System.GC.Server"), CLRConfig::UNSUPPORTED_gcServer))
104 {
105 startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_SERVER_GC);
106 }
107 if (Configuration::GetKnobBooleanValue(W("System.GC.RetainVM"), CLRConfig::UNSUPPORTED_GCRetainVM))
108 {
109 startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_HOARD_GC_VM);
110 }
111
112 *startupFlagsRef = startupFlags;
113}
114
115static void ConvertConfigPropertiesToUnicode(
116 const char** propertyKeys,
117 const char** propertyValues,
118 int propertyCount,
119 LPCWSTR** propertyKeysWRef,
120 LPCWSTR** propertyValuesWRef)
121{
122 LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount];
123 ASSERTE_ALL_BUILDS(propertyKeysW != nullptr);
124
125 LPCWSTR* propertyValuesW = new (nothrow) LPCWSTR[propertyCount];
126 ASSERTE_ALL_BUILDS(propertyValuesW != nullptr);
127
128 for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)
129 {
130 propertyKeysW[propertyIndex] = StringToUnicode(propertyKeys[propertyIndex]);
131 propertyValuesW[propertyIndex] = StringToUnicode(propertyValues[propertyIndex]);
132 }
133
134 *propertyKeysWRef = propertyKeysW;
135 *propertyValuesWRef = propertyValuesW;
136}
137
138#if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
139// Reference to the global holding the path to the JIT
140extern "C" LPCWSTR g_CLRJITPath;
141#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
142
143#ifdef FEATURE_GDBJIT
144GetInfoForMethodDelegate getInfoForMethodDelegate = NULL;
145extern "C" int coreclr_create_delegate(void*, unsigned int, const char*, const char*, const char*, void**);
146#endif //FEATURE_GDBJIT
147
148//
149// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
150//
151// Parameters:
152// exePath - Absolute path of the executable that invoked the ExecuteAssembly
153// appDomainFriendlyName - Friendly name of the app domain that will be created to execute the assembly
154// propertyCount - Number of properties (elements of the following two arguments)
155// propertyKeys - Keys of properties of the app domain
156// propertyValues - Values of properties of the app domain
157// hostHandle - Output parameter, handle of the created host
158// domainId - Output parameter, id of the created app domain
159//
160// Returns:
161// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
162//
163extern "C"
164int coreclr_initialize(
165 const char* exePath,
166 const char* appDomainFriendlyName,
167 int propertyCount,
168 const char** propertyKeys,
169 const char** propertyValues,
170 void** hostHandle,
171 unsigned int* domainId)
172{
173 HRESULT hr;
174#ifdef FEATURE_PAL
175 DWORD error = PAL_InitializeCoreCLR(exePath);
176 hr = HRESULT_FROM_WIN32(error);
177
178 // If PAL initialization failed, then we should return right away and avoid
179 // calling any other APIs because they can end up calling into the PAL layer again.
180 if (FAILED(hr))
181 {
182 return hr;
183 }
184#endif
185
186 ReleaseHolder<ICLRRuntimeHost4> host;
187
188 hr = CorHost2::CreateObject(IID_ICLRRuntimeHost4, (void**)&host);
189 IfFailRet(hr);
190
191 ConstWStringHolder appDomainFriendlyNameW = StringToUnicode(appDomainFriendlyName);
192
193 LPCWSTR* propertyKeysW;
194 LPCWSTR* propertyValuesW;
195 ConvertConfigPropertiesToUnicode(
196 propertyKeys,
197 propertyValues,
198 propertyCount,
199 &propertyKeysW,
200 &propertyValuesW);
201
202 // This will take ownership of propertyKeysWTemp and propertyValuesWTemp
203 Configuration::InitializeConfigurationKnobs(propertyCount, propertyKeysW, propertyValuesW);
204
205#if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
206 // Fetch the path to JIT binary, if specified
207 g_CLRJITPath = Configuration::GetKnobStringValue(W("JIT_PATH"));
208#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
209
210 STARTUP_FLAGS startupFlags;
211 InitializeStartupFlags(&startupFlags);
212
213 hr = host->SetStartupFlags(startupFlags);
214 IfFailRet(hr);
215
216 hr = host->Start();
217 IfFailRet(hr);
218
219 hr = host->CreateAppDomainWithManager(
220 appDomainFriendlyNameW,
221 // Flags:
222 // APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS
223 // - By default CoreCLR only allows platform neutral assembly to be run. To allow
224 // assemblies marked as platform specific, include this flag
225 //
226 // APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP
227 // - Allows sandboxed applications to make P/Invoke calls and use COM interop
228 //
229 // APPDOMAIN_SECURITY_SANDBOXED
230 // - Enables sandboxing. If not set, the app is considered full trust
231 //
232 // APPDOMAIN_IGNORE_UNHANDLED_EXCEPTION
233 // - Prevents the application from being torn down if a managed exception is unhandled
234 //
235 APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS |
236 APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP |
237 APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT,
238 NULL, // Name of the assembly that contains the AppDomainManager implementation
239 NULL, // The AppDomainManager implementation type name
240 propertyCount,
241 propertyKeysW,
242 propertyValuesW,
243 (DWORD *)domainId);
244
245 if (SUCCEEDED(hr))
246 {
247 host.SuppressRelease();
248 *hostHandle = host;
249#ifdef FEATURE_GDBJIT
250 HRESULT createDelegateResult;
251 createDelegateResult = coreclr_create_delegate(*hostHandle,
252 *domainId,
253 "SOS.NETCore",
254 "SOS.SymbolReader",
255 "GetInfoForMethod",
256 (void**)&getInfoForMethodDelegate);
257
258#if defined(_DEBUG)
259 if (!SUCCEEDED(createDelegateResult))
260 {
261 fprintf(stderr,
262 "Can't create delegate for 'SOS.SymbolReader.GetInfoForMethod' "
263 "method - status: 0x%08x\n", createDelegateResult);
264 }
265#endif // _DEBUG
266
267#endif
268 }
269 return hr;
270}
271
272//
273// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
274//
275// Parameters:
276// hostHandle - Handle of the host
277// domainId - Id of the domain
278//
279// Returns:
280// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
281//
282extern "C"
283int coreclr_shutdown(
284 void* hostHandle,
285 unsigned int domainId)
286{
287 ReleaseHolder<ICLRRuntimeHost4> host(reinterpret_cast<ICLRRuntimeHost4*>(hostHandle));
288
289 HRESULT hr = host->UnloadAppDomain(domainId, true); // Wait until done
290 IfFailRet(hr);
291
292 hr = host->Stop();
293
294#ifdef FEATURE_PAL
295 PAL_Shutdown();
296#endif
297
298 return hr;
299}
300
301//
302// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
303//
304// Parameters:
305// hostHandle - Handle of the host
306// domainId - Id of the domain
307// latchedExitCode - Latched exit code after domain unloaded
308//
309// Returns:
310// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
311//
312extern "C"
313int coreclr_shutdown_2(
314 void* hostHandle,
315 unsigned int domainId,
316 int* latchedExitCode)
317{
318 ReleaseHolder<ICLRRuntimeHost4> host(reinterpret_cast<ICLRRuntimeHost4*>(hostHandle));
319
320 HRESULT hr = host->UnloadAppDomain2(domainId, true, latchedExitCode); // Wait until done
321 IfFailRet(hr);
322
323 hr = host->Stop();
324
325#ifdef FEATURE_PAL
326 PAL_Shutdown();
327#endif
328
329 return hr;
330}
331
332//
333// Create a native callable delegate for a managed method.
334//
335// Parameters:
336// hostHandle - Handle of the host
337// domainId - Id of the domain
338// entryPointAssemblyName - Name of the assembly which holds the custom entry point
339// entryPointTypeName - Name of the type which holds the custom entry point
340// entryPointMethodName - Name of the method which is the custom entry point
341// delegate - Output parameter, the function stores a pointer to the delegate at the specified address
342//
343// Returns:
344// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
345//
346extern "C"
347int coreclr_create_delegate(
348 void* hostHandle,
349 unsigned int domainId,
350 const char* entryPointAssemblyName,
351 const char* entryPointTypeName,
352 const char* entryPointMethodName,
353 void** delegate)
354{
355 ICLRRuntimeHost4* host = reinterpret_cast<ICLRRuntimeHost4*>(hostHandle);
356
357 ConstWStringHolder entryPointAssemblyNameW = StringToUnicode(entryPointAssemblyName);
358 ConstWStringHolder entryPointTypeNameW = StringToUnicode(entryPointTypeName);
359 ConstWStringHolder entryPointMethodNameW = StringToUnicode(entryPointMethodName);
360
361 HRESULT hr = host->CreateDelegate(
362 domainId,
363 entryPointAssemblyNameW,
364 entryPointTypeNameW,
365 entryPointMethodNameW,
366 (INT_PTR*)delegate);
367
368 return hr;
369}
370
371//
372// Execute a managed assembly with given arguments
373//
374// Parameters:
375// hostHandle - Handle of the host
376// domainId - Id of the domain
377// argc - Number of arguments passed to the executed assembly
378// argv - Array of arguments passed to the executed assembly
379// managedAssemblyPath - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
380// exitCode - Exit code returned by the executed assembly
381//
382// Returns:
383// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
384//
385extern "C"
386int coreclr_execute_assembly(
387 void* hostHandle,
388 unsigned int domainId,
389 int argc,
390 const char** argv,
391 const char* managedAssemblyPath,
392 unsigned int* exitCode)
393{
394 if (exitCode == NULL)
395 {
396 return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
397 }
398 *exitCode = -1;
399
400 ICLRRuntimeHost4* host = reinterpret_cast<ICLRRuntimeHost4*>(hostHandle);
401
402 ConstWStringArrayHolder argvW;
403 argvW.Set(StringArrayToUnicode(argc, argv), argc);
404
405 ConstWStringHolder managedAssemblyPathW = StringToUnicode(managedAssemblyPath);
406
407 HRESULT hr = host->ExecuteAssembly(domainId, managedAssemblyPathW, argc, argvW, (DWORD *)exitCode);
408 IfFailRet(hr);
409
410 return hr;
411}
412