/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#include "dotnet_launcher.h"
-#include "utils.h"
+#include <dlfcn.h>
+#include <string>
+#include "coreclr_host.h"
#include "log.h"
+#include "utils.h"
+
+static const char* CLR_PATH = "/usr/share/dotnet.tizen/netcoreapp";
+static const char* TOOL_PATH = "/home/owner/share/.dotnet/tools";
+static const char* DIAGNOSTICS_TOOL_PATH = "/home/owner/share/tmp/sdk_tools/coreclr-diagnostics";
+
+void DisplayUsage() {
+ _SOUT(
+ "Execute a .NET application or command.\n\n"
+ "Usage: dotnet [options] [path-to-executable] [arguments]\n"
+ "Usage: dotnet [command] [arguments]\n\n"
+ "Options:\n"
+ "-h, --help show this help message\n"
+ "--clr-path <path> path to libcoreclr.so and runtime assemblies\n"
+ "--tool-path <path> path to the tool installation directory\n"
+ "--additionalprobingpath <path> path containing assemblies to probe for\n"
+ "--globalizationinvariant run in globalization invariant mode\n\n"
+ "Commands:\n"
+ "counters monitor or collect performance counters\n"
+ "dump capture or analyze a coredump\n"
+ "gcdump capture a heapdump\n"
+ "trace collect or convert a diagnostic event trace\n"
+ "stack reports the managed stacks\n");
+}
+
+int main(int argc, const char* argv[]) {
+#ifdef __arm__
+ // libunwind library is used to unwind stack frame, but libunwind for ARM
+ // does not support ARM vfpv3/NEON registers in DWARF format correctly.
+ // Therefore let's disable stack unwinding using DWARF information
+ // See https://github.com/dotnet/runtime/issues/6479
+ //
+ // libunwind use following methods to unwind stack frame.
+ // UNW_ARM_METHOD_ALL 0xFF
+ // UNW_ARM_METHOD_DWARF 0x01
+ // UNW_ARM_METHOD_FRAME 0x02
+ // UNW_ARM_METHOD_EXIDX 0x04
+ putenv(const_cast<char*>("UNW_ARM_UNWIND_METHOD=6"));
+#endif // __arm__
+
+ argv++;
+ argc--;
+
+ if (argc <= 0) {
+ DisplayUsage();
+ return -1;
+ }
+
+ std::string clrFilesPath(CLR_PATH);
+ std::string toolDllsPath(clrFilesPath + "/SOS");
+
+ std::string managedAssemblyPath;
+ std::string additionalProbingPath;
+ bool globalizationInvariant = false;
+
+ while (argc > 0) {
+ std::string arg(argv[0]);
+
+ if (arg == "-?" || arg == "-h" || arg == "--help") {
+ DisplayUsage();
+ return 0;
+ } else if (arg == "--clr-path" && argc > 1) {
+ clrFilesPath = argv[1];
+ argc--;
+ argv++;
+ } else if (arg == "--tool-path" && argc > 1) {
+ toolDllsPath = argv[1];
+ argc--;
+ argv++;
+ } else if (arg == "--additionalprobingpath" && argc > 1) {
+ additionalProbingPath = getAbsolutePath(argv[1]);
+ argc--;
+ argv++;
+ } else if (arg == "--globalizationinvariant") {
+ globalizationInvariant = true;
+ } else if ((arg == "--runtimeconfig" || arg == "--depsfile") && argc > 1) {
+ // Just for compatibility with corefx tests.
+ // See ParseArguments() in coreclr/hosts/unixcorerun/corerun.cpp.
+ argc--;
+ argv++;
+ } else if (arg.at(0) == '-') {
+ _SERR("Unknown option %s.", argv[0]);
+ DisplayUsage();
+ return -1;
+ } else if (isManagedAssembly(arg) || isNativeImage(arg)) {
+ if (!isFile(arg)) {
+ _SERR("The specified file does not exist.");
+ return -1;
+ }
+ managedAssemblyPath = arg;
+ argc--;
+ argv++;
+ break;
+ } else if (arg == "exec") {
+ // 'dotnet' and 'dotnet exec' can be alternatively used.
+ } else if (arg == "tool") {
+ _SERR("This command is not currently supported.");
+ return -1;
+ } else {
+ std::string toolDll = "/dotnet-" + arg + ".dll";
+ std::string searchToolPath1 = toolDllsPath + toolDll;
+ std::string searchToolPath2 = std::string(TOOL_PATH) + toolDll;
+ std::string searchToolPath3 = std::string(DIAGNOSTICS_TOOL_PATH) + toolDll;
+ if (isFile(searchToolPath1)) {
+ managedAssemblyPath = searchToolPath1;
+ } else if (isFile(searchToolPath2)) {
+ managedAssemblyPath = searchToolPath2;
+ } else if (isFile(searchToolPath3)) {
+ managedAssemblyPath = searchToolPath3;
+ } else {
+ _SERR(
+ "Could not execute because dotnet-%s does not exist.\n"
+ "Go to https://developer.samsung.com/tizen to learn how to install tools.\n", argv[0]);
+ return -1;
+ }
+
+ // Implicit compatibility mode for System.CommandLine.
+ std::string termValue(getenv("TERM"));
+ if (termValue == "linux") {
+ setenv("TERM", "xterm", 1);
+ }
+
+ argc--;
+ argv++;
+ break;
+ }
+
+ argc--;
+ argv++;
+ }
-using tizen::runtime::dotnetcore::CoreRuntime;
+ std::string currentExeAbsolutePath = getAbsolutePath("/proc/self/exe");
+ if (currentExeAbsolutePath.empty()) {
+ _SERR("Failed to get the current executable's absolute path.");
+ return -1;
+ }
-int main(int argc, char *argv[])
-{
- _INFO("##### Run in corerun mode #####");
+ std::string clrFilesAbsolutePath = getAbsolutePath(clrFilesPath);
+ if (clrFilesAbsolutePath.empty()) {
+ _SERR("Failed to resolve the full path to the CLR files.");
+ return -1;
+ }
- if (argc < 2) {
- _SOUT("No parameter");
+ std::string managedAssemblyAbsolutePath = getAbsolutePath(managedAssemblyPath);
+ if (managedAssemblyAbsolutePath.empty()) {
+ _SERR("Failed to get the managed assembly's absolute path.");
return -1;
}
- if (!isManagedAssembly(argv[1]) && !isNativeImage(argv[1])) {
- _SOUT("first parameter should be assembly file");
+ std::string coreclrLibPath(clrFilesAbsolutePath + "/libcoreclr.so");
+ std::string appPath = getBaseName(managedAssemblyAbsolutePath);
+ std::string nativeDllSearchDirs(appPath);
+ nativeDllSearchDirs += ":" + additionalProbingPath;
+ nativeDllSearchDirs += ":" + clrFilesAbsolutePath;
+
+ std::string tpaList(managedAssemblyAbsolutePath);
+ // For now we don't parse .deps.json file but let application DLLs can override runtime DLLs.
+ std::vector<std::string> tpaDirs = { appPath, additionalProbingPath, clrFilesAbsolutePath };
+ addAssembliesFromDirectories(tpaDirs, tpaList);
+
+ void* coreclrLib = dlopen(coreclrLibPath.c_str(), RTLD_NOW | RTLD_LOCAL);
+ if (coreclrLib == nullptr) {
+ const char* error = dlerror();
+ _SERR("dlopen failed to open the libcoreclr.so with error %s", error);
return -1;
}
- // remove executable and assembly path form the arguments and pass that to managed code
- int vargc = argc - 2;
- std::vector<char*> vargs;
- for (int i = 0; i < vargc; i++) {
- vargs.push_back(argv[2 + i]);
+ coreclr_initialize_ptr initializeCoreCLR = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
+ coreclr_execute_assembly_ptr executeAssembly = (coreclr_execute_assembly_ptr)dlsym(coreclrLib, "coreclr_execute_assembly");
+ coreclr_shutdown_ptr shutdownCoreCLR = (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown");
+
+ if (initializeCoreCLR == nullptr) {
+ _SERR("Function coreclr_initialize not found in the libcoreclr.so");
+ return -1;
+ } else if (executeAssembly == nullptr) {
+ _SERR("Function coreclr_execute_assembly not found in the libcoreclr.so");
+ return -1;
+ } else if (shutdownCoreCLR == nullptr) {
+ _SERR("Function coreclr_shutdown not found in the libcoreclr.so");
+ return -1;
}
- // set command name to assembly file
- char* fileName = getFileNameFromPath(argv[1]);
- setCmdName(fileName);
-
- CoreRuntime* runtime = new CoreRuntime("corerun");
+ bool ncdbStartupHook = isNCDBStartupHookProvided();
+
+ const char* propertyKeys[] = {
+ "TRUSTED_PLATFORM_ASSEMBLIES",
+ "APP_PATHS",
+ "APP_NI_PATHS",
+ "NATIVE_DLL_SEARCH_DIRECTORIES",
+ "System.Globalization.Invariant",
+ ncdbStartupHook ? "STARTUP_HOOKS" : "" // must be the last one
+ };
+ const char* propertyValues[] = {
+ tpaList.c_str(),
+ appPath.c_str(),
+ appPath.c_str(),
+ nativeDllSearchDirs.c_str(),
+ globalizationInvariant ? "true" : "false",
+ ncdbStartupHook ? getNCDBStartupHook() : "" // must be the last one
+ };
+
+ void* hostHandle;
+ unsigned int domainId;
- // get absolute path of input dll file
- std::string absoluteDllPath = absolutePath(argv[1]);
+ int st = initializeCoreCLR(
+ currentExeAbsolutePath.c_str(),
+ "dotnet",
+ sizeof(propertyKeys) / sizeof(propertyKeys[0]) - (ncdbStartupHook ? 0 : 1),
+ propertyKeys,
+ propertyValues,
+ &hostHandle,
+ &domainId);
- if (runtime->initialize(LaunchMode::corerun, false, absoluteDllPath.c_str()) != 0) {
- _SOUT("Failed to initialize");
+ if (st < 0) {
+ _SERR("coreclr_initialize failed - status: 0x%08x", st);
return -1;
}
- // launch application
- if (runtime->launch(fileName, baseName(absoluteDllPath).c_str(), absoluteDllPath.c_str(), vargc, &vargs[0])) {
- _SOUT("Failed to launch");
+ // Set the current process's command name.
+ std::string managedAssemblyName = getFileName(managedAssemblyAbsolutePath);
+ setCmdName(managedAssemblyName);
+
+ int exitCode = -1;
+
+ st = executeAssembly(
+ hostHandle,
+ domainId,
+ argc,
+ argv,
+ managedAssemblyAbsolutePath.c_str(),
+ (unsigned int*)&exitCode);
+
+ if (st < 0) {
+ _SERR("coreclr_execute_assembly failed - status: 0x%08x", st);
+ exitCode = -1;
+ }
+
+ st = shutdownCoreCLR(hostHandle, domainId);
+ if (st < 0) {
+ _SERR("coreclr_shutdown failed - status: 0x%08x", st);
return -1;
}
- return 0;
+ return exitCode;
}
-