This repository has been archived by the owner on Jun 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
/
coreclrutil.cpp
332 lines (288 loc) · 9.34 KB
/
coreclrutil.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/*
**==============================================================================
**
** Copyright (c) Microsoft Corporation. All rights reserved. See file LICENSE
** for license information.
**
**==============================================================================
*/
#include "coreclrutil.h"
#include <dirent.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string>
#include <set>
#include <cstdlib>
#include "base/logbase.h"
// The name of the CoreCLR native runtime DLL
#if defined(__APPLE__)
const std::string coreClrDll = "/libcoreclr.dylib";
#else
const std::string coreClrDll = "/libcoreclr.so";
#endif
void* coreclrLib;
// Prototype of the coreclr_initialize function from the libcoreclr.so
typedef int (*InitializeCoreCLRFunction)(
const char* exePath,
const char* appDomainFriendlyName,
int propertyCount,
const char** propertyKeys,
const char** propertyValues,
void** hostHandle,
unsigned int* domainId);
// Prototype of the coreclr_shutdown function from the libcoreclr.so
typedef int (*ShutdownCoreCLRFunction)(
void* hostHandle,
unsigned int domainId);
InitializeCoreCLRFunction initializeCoreCLR;
ShutdownCoreCLRFunction shutdownCoreCLR;
ExecuteAssemblyFunction executeAssembly;
CreateDelegateFunction createDelegate;
//
// Get the absolute path given the environment variable.
//
std::string GetEnvAbsolutePath(const char* env)
{
char fullpath[PATH_MAX + 1];
const char* local = std::getenv(env);
if (!local)
{
return std::string("");
}
char *ptr = realpath(local, fullpath);
if (!ptr)
{
__LOGE(("Invalid environment variable %s content, switching to default value. ", env));
return std::string("");
}
return std::string(ptr);
}
// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string.
// Note: copied from unixcorerun
void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList)
{
const char * const tpaExtensions[] = {
".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
".dll",
".ni.exe",
".exe",
};
DIR* dir = opendir(directory);
if (dir == NULL)
{
return;
}
std::set<std::string> addedAssemblies;
// Walk the directory for each extension separately so that we first get files with .ni.dll extension,
// then files with .dll extension, etc.
for (unsigned int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++)
{
const char* ext = tpaExtensions[extIndex];
int extLength = strlen(ext);
struct dirent* entry;
// For all entries in the directory
while ((entry = readdir(dir)) != NULL)
{
// We are interested in files only
switch (entry->d_type)
{
case DT_REG:
break;
// Handle symlinks and file systems that do not support d_type
case DT_LNK:
case DT_UNKNOWN:
{
std::string fullFilename;
fullFilename.append(directory);
fullFilename.append("/");
fullFilename.append(entry->d_name);
struct stat sb;
if (stat(fullFilename.c_str(), &sb) == -1)
{
continue;
}
if (!S_ISREG(sb.st_mode))
{
continue;
}
}
break;
default:
continue;
}
std::string filename(entry->d_name);
// Check if the extension matches the one we are looking for
int extPos = filename.length() - extLength;
if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0))
{
continue;
}
std::string filenameWithoutExt(filename.substr(0, extPos));
// Make sure if we have an assembly with multiple extensions present,
// we insert only one version of it.
if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end())
{
addedAssemblies.insert(filenameWithoutExt);
tpaList.append(directory);
tpaList.append("/");
tpaList.append(filename);
tpaList.append(":");
}
}
// Rewind the directory stream to be able to iterate over it for the next extension
rewinddir(dir);
}
closedir(dir);
}
//
// Below is our custom start/stop interface
//
int startCoreCLR(
const char* appDomainFriendlyName,
void** hostHandle,
unsigned int* domainId)
{
char exePath[PATH_MAX];
// get path to current executable
ssize_t len = readlink("/proc/self/exe", exePath, PATH_MAX);
if (len == -1 || len == sizeof(exePath))
len = 0;
exePath[len] = '\0';
// get the CoreCLR root path
std::string clrAbsolutePath = GetEnvAbsolutePath("CORE_ROOT");
if (clrAbsolutePath.empty())
{
#if defined(__APPLE__)
clrAbsolutePath = std::string("/usr/local/bin/pwsh");
#else
clrAbsolutePath = std::string("/usr/bin/pwsh");
#endif
char realPath[PATH_MAX + 1];
char *ptr = realpath(clrAbsolutePath.c_str(), realPath);
if (ptr == NULL)
{
clrAbsolutePath = std::string("");
}
else
{
std::string followedPath(realPath);
size_t index = followedPath.find_last_of("/\\");
if (index == std::string::npos)
{
clrAbsolutePath = std::string("");
}
else
{
clrAbsolutePath = followedPath.substr(0, index);
}
}
}
if (clrAbsolutePath.empty())
{
#if defined(__APPLE__)
clrAbsolutePath = std::string("/usr/local/microsoft/powershell");
#else
clrAbsolutePath = std::string("/opt/microsoft/powershell");
#endif
}
// get the CoreCLR shared library path
std::string coreClrDllPath(clrAbsolutePath);
coreClrDllPath += coreClrDll;
// open the shared library
coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL);
if (coreclrLib == NULL)
{
__LOGE(("dlopen failed to open the CoreCLR library: %s ", dlerror()));
return -1;
}
// query and verify the function pointers
initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize");
shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown");
executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly");
createDelegate = (CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate");
if (initializeCoreCLR == NULL)
{
__LOGE(("function coreclr_initialize not found in CoreCLR library"));
return -1;
}
if (executeAssembly == NULL)
{
__LOGE(("function coreclr_execute_assembly not found in CoreCLR library"));
return -1;
}
if (shutdownCoreCLR == NULL)
{
__LOGE(("function coreclr_shutdown not found in CoreCLR library"));
return -1;
}
if (createDelegate == NULL)
{
__LOGE(("function coreclr_create_delegate not found in CoreCLR library"));
return -1;
}
// generate the Trusted Platform Assemblies list
std::string tpaList;
// add assemblies in the CoreCLR root path
AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(), tpaList);
// create list of properties to initialize CoreCLR
const char* propertyKeys[] = {
"TRUSTED_PLATFORM_ASSEMBLIES",
"APP_PATHS",
"APP_NI_PATHS",
"NATIVE_DLL_SEARCH_DIRECTORIES",
"PLATFORM_RESOURCE_ROOTS",
"AppDomainCompatSwitch",
"SERVER_GC",
"APP_CONTEXT_BASE_DIRECTORY"
};
// We use the CORE_ROOT for just about everything: trusted
// platform assemblies, DLLs, native DLLs, resources, and the
// AppContext.BaseDirectory. Server garbage collection is disabled
// by default because of dotnet/cli#652
const char* propertyValues[] = {
// TRUSTED_PLATFORM_ASSEMBLIES
tpaList.c_str(),
// APP_PATHS
clrAbsolutePath.c_str(),
// APP_NI_PATHS
clrAbsolutePath.c_str(),
// NATIVE_DLL_SEARCH_DIRECTORIES
clrAbsolutePath.c_str(),
// PLATFORM_RESOURCE_ROOTS
clrAbsolutePath.c_str(),
// AppDomainCompatSwitch
"UseLatestBehaviorWhenTFMNotSpecified",
// SERVER_GC
"0",
// APP_CONTEXT_BASE_DIRECTORY
clrAbsolutePath.c_str()
};
// initialize CoreCLR
int status = initializeCoreCLR(
exePath,
appDomainFriendlyName,
sizeof(propertyKeys)/sizeof(propertyKeys[0]),
propertyKeys,
propertyValues,
hostHandle,
domainId);
return status;
}
int stopCoreCLR(void* hostHandle, unsigned int domainId)
{
// shutdown CoreCLR
int status = shutdownCoreCLR(hostHandle, domainId);
if (!SUCCEEDED(status))
{
__LOGE(("coreclr_shutdown failed - status: %X", status));
}
// close the dynamic library
if (0 != dlclose(coreclrLib))
{
__LOGE(("failed to close CoreCLR library"));
}
return status;
}