820679bdd62a2fb8d2b264ee048bd28ac5682d94
[platform/core/dotnet/launcher.git] / NativeLauncher / launcher / exec / corerun.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <dlfcn.h>
18 #include <string>
19 #include "coreclr_host.h"
20 #include "log.h"
21 #include "utils.h"
22 #include "r2r_checker.h"
23
24 static const char* CLR_PATH = "/usr/share/dotnet.tizen/netcoreapp";
25 static const char* TOOL_PATH = "/home/owner/share/.dotnet/tools";
26 static const char* DIAGNOSTICS_TOOL_PATH = "/home/owner/share/tmp/sdk_tools/coreclr-diagnostics";
27
28 void DisplayUsage() {
29         _SOUT(
30                 "Execute a .NET application or command.\n\n"
31                 "Usage: dotnet [options] [path-to-executable] [arguments]\n"
32                 "Usage: dotnet [command] [arguments]\n\n"
33                 "Options:\n"
34                 "-h, --help                         show this help message\n"
35                 "--clr-path <path>                  path to libcoreclr.so and runtime assemblies\n"
36                 "--tool-path <path>                 path to the tool installation directory\n"
37                 "--additionalprobingpath <path>     path containing assemblies to probe for\n"
38                 "--globalizationinvariant           run in globalization invariant mode\n\n"
39                 "Commands:\n"
40                 "counters       monitor or collect performance counters\n"
41                 "dump           capture or analyze a coredump\n"
42                 "gcdump         capture a heapdump\n"
43                 "trace          collect or convert a diagnostic event trace\n"
44                 "stack          reports the managed stacks\n");
45 }
46
47 int main(int argc, const char* argv[]) {
48 #ifdef __arm__
49         // libunwind library is used to unwind stack frame, but libunwind for ARM
50         // does not support ARM vfpv3/NEON registers in DWARF format correctly.
51         // Therefore let's disable stack unwinding using DWARF information
52         // See https://github.com/dotnet/runtime/issues/6479
53         //
54         // libunwind use following methods to unwind stack frame.
55         // UNW_ARM_METHOD_ALL          0xFF
56         // UNW_ARM_METHOD_DWARF        0x01
57         // UNW_ARM_METHOD_FRAME        0x02
58         // UNW_ARM_METHOD_EXIDX        0x04
59         putenv(const_cast<char*>("UNW_ARM_UNWIND_METHOD=6"));
60 #endif // __arm__
61
62         argv++;
63         argc--;
64
65         if (argc <= 0) {
66                 DisplayUsage();
67                 return -1;
68         }
69
70         std::string clrFilesPath(CLR_PATH);
71         std::string toolDllsPath(clrFilesPath + "/SOS");
72
73         std::string managedAssemblyPath;
74         std::string additionalProbingPath;
75         bool globalizationInvariant = false;
76
77         while (argc > 0) {
78                 std::string arg(argv[0]);
79
80                 if (arg == "-?" || arg == "-h" || arg == "--help") {
81                         DisplayUsage();
82                         return 0;
83                 } else if (arg == "--clr-path" && argc > 1) {
84                         clrFilesPath = argv[1];
85                         argc--;
86                         argv++;
87                 } else if (arg == "--tool-path" && argc > 1) {
88                         toolDllsPath = argv[1];
89                         argc--;
90                         argv++;
91                 } else if (arg == "--additionalprobingpath" && argc > 1) {
92                         additionalProbingPath = getAbsolutePath(argv[1]);
93                         argc--;
94                         argv++;
95                 } else if (arg == "--globalizationinvariant") {
96                         globalizationInvariant = true;
97                 } else if ((arg == "--runtimeconfig" || arg == "--depsfile") && argc > 1) {
98                         // Just for compatibility with corefx tests.
99                         // See ParseArguments() in coreclr/hosts/unixcorerun/corerun.cpp.
100                         argc--;
101                         argv++;
102                 } else if (arg.at(0) == '-') {
103                         _SERR("Unknown option %s.", argv[0]);
104                         DisplayUsage();
105                         return -1;
106                 } else if (isManagedAssembly(arg) || isR2RImage(arg)) {
107                         if (!isFile(arg)) {
108                                 _SERR("The specified file does not exist.");
109                                 return -1;
110                         }
111                         managedAssemblyPath = arg;
112                         argc--;
113                         argv++;
114                         break;
115                 } else if (arg == "exec") {
116                         // 'dotnet' and 'dotnet exec' can be alternatively used.
117                 } else if (arg == "tool") {
118                         _SERR("This command is not currently supported.");
119                         return -1;
120                 } else {
121                         std::string toolDll = "/dotnet-" + arg + ".dll";
122                         std::string searchToolPath1 = toolDllsPath + toolDll;
123                         std::string searchToolPath2 = std::string(TOOL_PATH) + toolDll;
124                         std::string searchToolPath3 = std::string(DIAGNOSTICS_TOOL_PATH) + toolDll;
125                         if (isFile(searchToolPath1)) {
126                                 managedAssemblyPath = searchToolPath1;
127                         } else if (isFile(searchToolPath2)) {
128                                 managedAssemblyPath = searchToolPath2;
129                         } else if (isFile(searchToolPath3)) {
130                                 managedAssemblyPath = searchToolPath3;
131                         } else {
132                                 _SERR(
133                                         "Could not execute because dotnet-%s does not exist.\n"
134                                         "Go to https://developer.samsung.com/tizen to learn how to install tools.\n", argv[0]);
135                                 return -1;
136                         }
137
138                         // Implicit compatibility mode for System.CommandLine.
139                         std::string termValue(getenv("TERM"));
140                         if (termValue == "linux") {
141                                 setenv("TERM", "xterm", 1);
142                         }
143
144                         argc--;
145                         argv++;
146                         break;
147                 }
148
149                 argc--;
150                 argv++;
151         }
152
153         std::string currentExeAbsolutePath = getAbsolutePath("/proc/self/exe");
154         if (currentExeAbsolutePath.empty()) {
155                 _SERR("Failed to get the current executable's absolute path.");
156                 return -1;
157         }
158
159         std::string clrFilesAbsolutePath = getAbsolutePath(clrFilesPath);
160         if (clrFilesAbsolutePath.empty()) {
161                 _SERR("Failed to resolve the full path to the CLR files.");
162                 return -1;
163         }
164
165         std::string managedAssemblyAbsolutePath = getAbsolutePath(managedAssemblyPath);
166         if (managedAssemblyAbsolutePath.empty()) {
167                 _SERR("Failed to get the managed assembly's absolute path.");
168                 return -1;
169         }
170
171         std::string coreclrLibPath(clrFilesAbsolutePath + "/libcoreclr.so");
172         std::string appPath = getBaseName(managedAssemblyAbsolutePath);
173         std::string nativeDllSearchDirs(appPath);
174         nativeDllSearchDirs += ":" + additionalProbingPath;
175         nativeDllSearchDirs += ":" + clrFilesAbsolutePath;
176
177         std::string tpaList(managedAssemblyAbsolutePath);
178         // For now we don't parse .deps.json file but let application DLLs can override runtime DLLs.
179         std::vector<std::string> tpaDirs = { appPath, additionalProbingPath, clrFilesAbsolutePath };
180         addAssembliesFromDirectories(tpaDirs, tpaList);
181
182         void* coreclrLib = dlopen(coreclrLibPath.c_str(), RTLD_NOW | RTLD_LOCAL);
183         if (coreclrLib == nullptr) {
184                 const char* error = dlerror();
185                 _SERR("dlopen failed to open the libcoreclr.so with error %s", error);
186                 return -1;
187         }
188
189         coreclr_initialize_ptr initializeCoreCLR = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
190         coreclr_execute_assembly_ptr executeAssembly = (coreclr_execute_assembly_ptr)dlsym(coreclrLib, "coreclr_execute_assembly");
191         coreclr_shutdown_ptr shutdownCoreCLR = (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown");
192
193         if (initializeCoreCLR == nullptr) {
194                 _SERR("Function coreclr_initialize not found in the libcoreclr.so");
195                 return -1;
196         } else if (executeAssembly == nullptr) {
197                 _SERR("Function coreclr_execute_assembly not found in the libcoreclr.so");
198                 return -1;
199         } else if (shutdownCoreCLR == nullptr) {
200                 _SERR("Function coreclr_shutdown not found in the libcoreclr.so");
201                 return -1;
202         }
203
204         bool ncdbStartupHook = isNCDBStartupHookProvided();
205
206         const char* propertyKeys[] = {
207                 "TRUSTED_PLATFORM_ASSEMBLIES",
208                 "APP_PATHS",
209                 "APP_NI_PATHS",
210                 "NATIVE_DLL_SEARCH_DIRECTORIES",
211                 "System.Globalization.Invariant",
212                 ncdbStartupHook ? "STARTUP_HOOKS" : "" // must be the last one
213         };
214         const char* propertyValues[] = {
215                 tpaList.c_str(),
216                 appPath.c_str(),
217                 appPath.c_str(),
218                 nativeDllSearchDirs.c_str(),
219                 globalizationInvariant ? "true" : "false",
220                 ncdbStartupHook ? getNCDBStartupHook() : "" // must be the last one
221         };
222
223         void* hostHandle;
224         unsigned int domainId;
225
226         int st = initializeCoreCLR(
227                 currentExeAbsolutePath.c_str(),
228                 "dotnet",
229                 sizeof(propertyKeys) / sizeof(propertyKeys[0]) - (ncdbStartupHook ? 0 : 1),
230                 propertyKeys,
231                 propertyValues,
232                 &hostHandle,
233                 &domainId);
234
235         if (st < 0) {
236                 _SERR("coreclr_initialize failed - status: 0x%08x", st);
237                 return -1;
238         }
239
240         // Set the current process's command name.
241         std::string managedAssemblyName = getFileName(managedAssemblyAbsolutePath);
242         setCmdName(managedAssemblyName);
243
244         int exitCode = -1;
245
246         st = executeAssembly(
247                 hostHandle,
248                 domainId,
249                 argc,
250                 argv,
251                 managedAssemblyAbsolutePath.c_str(),
252                 (unsigned int*)&exitCode);
253
254         if (st < 0) {
255                 _SERR("coreclr_execute_assembly failed - status: 0x%08x", st);
256                 exitCode = -1;
257         }
258
259         st = shutdownCoreCLR(hostHandle, domainId);
260         if (st < 0) {
261                 _SERR("coreclr_shutdown failed - status: 0x%08x", st);
262                 return -1;
263         }
264
265         return exitCode;
266 }