isNativeImage = false;
HRESULT pathResult = S_OK;
- IF_FAIL_GO(pathResult = GetNextPath(paths, startPos, outPath));
- if (pathResult == S_FALSE)
+ while(true)
{
- return S_FALSE;
- }
-
- if (Path::IsRelative(outPath))
- {
- GO_WITH_HRESULT(E_INVALIDARG);
- }
-
- {
- // Find the beginning of the simple name
- SString::CIterator iSimpleNameStart = outPath.End();
-
- if (!outPath.FindBack(iSimpleNameStart, DIRECTORY_SEPARATOR_CHAR_W))
- {
- iSimpleNameStart = outPath.Begin();
- }
- else
+ IF_FAIL_GO(pathResult = GetNextPath(paths, startPos, outPath));
+ if (pathResult == S_FALSE)
{
- // Advance past the directory separator to the first character of the file name
- iSimpleNameStart++;
+ return S_FALSE;
}
- if (iSimpleNameStart == outPath.End())
+ if (Path::IsRelative(outPath))
{
GO_WITH_HRESULT(E_INVALIDARG);
}
- const SString sNiDll(SString::Literal, W(".ni.dll"));
- const SString sNiExe(SString::Literal, W(".ni.exe"));
- const SString sDll(SString::Literal, W(".dll"));
- const SString sExe(SString::Literal, W(".exe"));
-
- if (!dllOnly && (outPath.EndsWithCaseInsensitive(sNiDll) ||
- outPath.EndsWithCaseInsensitive(sNiExe)))
- {
- simpleName.Set(outPath, iSimpleNameStart, outPath.End() - 7);
- isNativeImage = true;
- }
- else if (outPath.EndsWithCaseInsensitive(sDll) ||
- (!dllOnly && outPath.EndsWithCaseInsensitive(sExe)))
- {
- simpleName.Set(outPath, iSimpleNameStart, outPath.End() - 4);
- }
- else
{
- // Invalid filename
- GO_WITH_HRESULT(E_INVALIDARG);
+ // Find the beginning of the simple name
+ SString::CIterator iSimpleNameStart = outPath.End();
+
+ if (!outPath.FindBack(iSimpleNameStart, DIRECTORY_SEPARATOR_CHAR_W))
+ {
+ iSimpleNameStart = outPath.Begin();
+ }
+ else
+ {
+ // Advance past the directory separator to the first character of the file name
+ iSimpleNameStart++;
+ }
+
+ if (iSimpleNameStart == outPath.End())
+ {
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+
+ const SString sNiDll(SString::Literal, W(".ni.dll"));
+ const SString sNiExe(SString::Literal, W(".ni.exe"));
+ const SString sDll(SString::Literal, W(".dll"));
+ const SString sExe(SString::Literal, W(".exe"));
+
+ if (dllOnly && (outPath.EndsWithCaseInsensitive(sExe) ||
+ outPath.EndsWithCaseInsensitive(sNiExe)))
+ {
+ // Skip exe files when the caller requested only dlls
+ continue;
+ }
+
+ if (outPath.EndsWithCaseInsensitive(sNiDll) ||
+ outPath.EndsWithCaseInsensitive(sNiExe))
+ {
+ simpleName.Set(outPath, iSimpleNameStart, outPath.End() - 7);
+ isNativeImage = true;
+ }
+ else if (outPath.EndsWithCaseInsensitive(sDll) ||
+ outPath.EndsWithCaseInsensitive(sExe))
+ {
+ simpleName.Set(outPath, iSimpleNameStart, outPath.End() - 4);
+ }
+ else
+ {
+ // Invalid filename
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+
+ break;
}
}
*propertyValuesWRef = propertyValuesW;
}
+coreclr_error_writer_callback_fn g_errorWriter = nullptr;
+
+//
+// Set callback for writing error logging
+//
+// Parameters:
+// errorWriter - callback that will be called for each line of the error info
+// - passing in NULL removes a callback that was previously set
+//
+// Returns:
+// S_OK
+//
+extern "C"
+DLLEXPORT
+int coreclr_set_error_writer(coreclr_error_writer_callback_fn error_writer)
+{
+ g_errorWriter = error_writer;
+ return S_OK;
+}
+
#ifdef FEATURE_GDBJIT
GetInfoForMethodDelegate getInfoForMethodDelegate = NULL;
extern "C" int coreclr_create_delegate(void*, unsigned int, const char*, const char*, const char*, void**);
return hr;
}
+
+void LogErrorToHost(const char* format, ...)
+{
+ if (g_errorWriter != NULL)
+ {
+ char messageBuffer[1024];
+ va_list args;
+ va_start(args, format);
+ _vsnprintf_s(messageBuffer, ARRAY_SIZE(messageBuffer), _TRUNCATE, format, args);
+ g_errorWriter(messageBuffer);
+ va_end(args);
+ }
+}
coreclr_create_delegate
coreclr_execute_assembly
coreclr_initialize
+ coreclr_set_error_writer
coreclr_shutdown
coreclr_shutdown_2
coreclr_create_delegate
coreclr_execute_assembly
coreclr_initialize
+coreclr_set_error_writer
coreclr_shutdown
coreclr_shutdown_2
static uint32_t GetCurrentProcessCpuCount();
static void DiagAddNewRegion(int generation, uint8_t* rangeStart, uint8_t* rangeEnd, uint8_t* rangeEndReserved);
+
+ static void LogErrorToHost(const char *message);
};
#endif // __GCENV_EE_H__
gc_log = CreateLogFile(GCConfig::GetLogFile(), false);
if (gc_log == NULL)
+ {
+ GCToEEInterface::LogErrorToHost("Cannot create log file");
return E_FAIL;
+ }
// GCLogFileSize in MBs.
gc_log_file_size = static_cast<size_t>(GCConfig::GetLogFileSize());
if (gc_log_file_size <= 0 || gc_log_file_size > 500)
{
+ GCToEEInterface::LogErrorToHost("Invalid log file size (valid size needs to be larger than 0 and smaller than 500)");
fclose (gc_log);
return E_FAIL;
}
if (!gc_log_buffer)
{
fclose(gc_log);
- return E_FAIL;
+ return E_OUTOFMEMORY;
}
memset (gc_log_buffer, '*', gc_log_buffer_size);
gc_config_log = CreateLogFile(GCConfig::GetConfigLogFile(), true);
if (gc_config_log == NULL)
+ {
+ GCToEEInterface::LogErrorToHost("Cannot create log file");
return E_FAIL;
+ }
gc_config_log_buffer = new (nothrow) uint8_t [gc_config_log_buffer_size];
if (!gc_config_log_buffer)
{
fclose(gc_config_log);
- return E_FAIL;
+ return E_OUTOFMEMORY;
}
compact_ratio = static_cast<int>(GCConfig::GetCompactRatio());
else
{
assert (!"cannot use regions without specifying the range!!!");
+ GCToEEInterface::LogErrorToHost("Cannot use regions without specifying the range (using DOTNET_GCRegionRange)");
return E_FAIL;
}
#else //USE_REGIONS
if (!init_semi_shared())
{
+ GCToEEInterface::LogErrorToHost("PER_HEAP_ISOLATED data members initialization failed");
hres = E_FAIL;
}
if (!WaitForGCEvent->CreateManualEventNoThrow(TRUE))
{
+ GCToEEInterface::LogErrorToHost("Creation of WaitForGCEvent failed");
return E_FAIL;
}
int hb_info_size_per_node = hb_info_size_per_proc * procs_per_numa_node;
uint8_t* numa_mem = (uint8_t*)GCToOSInterface::VirtualReserve (hb_info_size_per_node, 0, 0, numa_node_index);
if (!numa_mem)
+ {
+ GCToEEInterface::LogErrorToHost("Reservation of numa_mem failed");
return E_FAIL;
+ }
if (!GCToOSInterface::VirtualCommit (numa_mem, hb_info_size_per_node, numa_node_index))
+ {
+ GCToEEInterface::LogErrorToHost("Commit of numa_mem failed");
return E_FAIL;
+ }
heap_balance_info_proc* hb_info_procs = (heap_balance_info_proc*)numa_mem;
hb_info_numa_nodes[numa_node_index].hb_info_procs = hb_info_procs;
IGCHandleManager* g_theGCHandleManager;
#ifdef BUILD_AS_STANDALONE
-IGCToCLR* g_theGCToCLR;
+IGCToCLR2* g_theGCToCLR;
VersionInfo g_runtimeSupportedVersion;
#endif // BUILD_AS_STANDALONE
// The singular interface instance. All calls in GCToEEInterface
// will be forwarded to this interface instance.
-extern IGCToCLR* g_theGCToCLR;
+extern IGCToCLR2* g_theGCToCLR;
// GC version that the current runtime supports
extern VersionInfo g_runtimeSupportedVersion;
g_theGCToCLR->DiagAddNewRegion(generation, rangeStart, rangeEnd, rangeEndReserved);
}
+inline void GCToEEInterface::LogErrorToHost(const char *message)
+{
+ if (g_runtimeSupportedVersion.MajorVersion >= GC_INTERFACE2_MAJOR_VERSION)
+ {
+ g_theGCToCLR->LogErrorToHost(message);
+ }
+}
+
#endif // __GCTOENV_EE_STANDALONE_INL__
void DiagAddNewRegion(int generation, uint8_t* rangeStart, uint8_t* rangeEnd, uint8_t* rangeEndReserved) = 0;
};
+class IGCToCLR2 : public IGCToCLR {
+public:
+
+ virtual
+ void LogErrorToHost(const char *message) = 0;
+};
+
#endif // _GCINTERFACE_EE_H_
// The major version of the GC/EE interface. Breaking changes to this interface
// require bumps in the major version number.
-#define GC_INTERFACE_MAJOR_VERSION 5
+#define GC_INTERFACE_MAJOR_VERSION 6
// The minor version of the GC/EE interface. Non-breaking changes are required
// to bump the minor version number. GCs and EEs with minor version number
// mismatches can still interopate correctly, with some care.
#define GC_INTERFACE_MINOR_VERSION 1
+// The major version of the GC/EE interface. Breaking changes to this interface
+// require bumps in the major version number.
+#define GC_INTERFACE2_MAJOR_VERSION 6
+
struct ScanContext;
struct gc_alloc_context;
class CrawlFrame;
#ifdef BUILD_AS_STANDALONE
assert(clrToGC != nullptr);
- g_theGCToCLR = clrToGC;
+ g_theGCToCLR = (IGCToCLR2*)clrToGC;
#else
UNREFERENCED_PARAMETER(clrToGC);
assert(clrToGC == nullptr);
if (!GCToOSInterface::Initialize())
{
+ GCToEEInterface::LogErrorToHost("Failed to initialize GCToOSInterface");
return E_FAIL;
}
#endif
void GCToEEInterface::DiagAddNewRegion(int generation, uint8_t* rangeStart, uint8_t* rangeEnd, uint8_t* rangeEndReserved)
{
}
+
+void GCToEEInterface::LogErrorToHost(const char *message)
+{
+}
static void* CurrentClrInstance;
static unsigned int CurrentAppDomainId;
+static void log_error_info(const char* line)
+{
+ std::fprintf(stderr, "%s\n", line);
+}
+
static int run(const configuration& config)
{
platform_specific_actions actions;
// Get CoreCLR exports
coreclr_initialize_ptr coreclr_init_func = nullptr;
coreclr_execute_assembly_ptr coreclr_execute_func = nullptr;
+ coreclr_set_error_writer_ptr coreclr_set_error_writer_func = nullptr;
coreclr_shutdown_2_ptr coreclr_shutdown2_func = nullptr;
if (!try_get_export(coreclr_mod, "coreclr_initialize", (void**)&coreclr_init_func)
|| !try_get_export(coreclr_mod, "coreclr_execute_assembly", (void**)&coreclr_execute_func)
return -1;
}
+ // The coreclr_set_error_writer is optional
+ (void)try_get_export(coreclr_mod, "coreclr_set_error_writer", (void**)&coreclr_set_error_writer_func);
+
// Construct CoreCLR properties.
pal::string_utf8_t tpa_list_utf8 = pal::convert_to_utf8(tpa_list.c_str());
pal::string_utf8_t app_path_utf8 = pal::convert_to_utf8(app_path.c_str());
propertyCount, propertyKeys.data(), propertyValues.data(),
entry_assembly_utf8.c_str(), config.entry_assembly_argc, argv_utf8.get() };
+ if (coreclr_set_error_writer_func != nullptr)
+ {
+ coreclr_set_error_writer_func(log_error_info);
+ }
+
int result;
result = coreclr_init_func(
exe_path_utf8.c_str(),
return -1;
}
+ if (coreclr_set_error_writer_func != nullptr)
+ {
+ coreclr_set_error_writer_func(nullptr);
+ }
+
int exit_code;
{
actions.before_execute_assembly(config.entry_assembly_fullpath);
unsigned int* domainId);
//
+// Type of the callback function that can be set by the coreclr_set_error_writer
+//
+typedef void (*coreclr_error_writer_callback_fn) (const char *message);
+
+//
+// Set callback for writing error logging
+//
+// Parameters:
+// errorWriter - callback that will be called for each line of the error info
+// - passing in NULL removes a callback that was previously set
+//
+// Returns:
+// S_OK
+//
+CORECLR_HOSTING_API(coreclr_set_error_writer,
+ coreclr_error_writer_callback_fn errorWriter);
+
+//
// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
//
// Parameters:
return true;
}
+void GCToEEInterface::LogErrorToHost(const char *message)
+{
+}
+
bool GCToEEInterface::GetStringConfigValue(const char* privateKey, const char* publicKey, const char** value)
{
UNREFERENCED_PARAMETER(privateKey);
ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
- m_pSystemPEAssembly = PEAssembly::OpenSystem();
+ EX_TRY
+ {
+ m_pSystemPEAssembly = PEAssembly::OpenSystem();
- // Only partially load the system assembly. Other parts of the code will want to access
- // the globals in this function before finishing the load.
- m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemPEAssembly, FILE_LOAD_POST_LOADLIBRARY)->GetAssembly();
+ // Only partially load the system assembly. Other parts of the code will want to access
+ // the globals in this function before finishing the load.
+ m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemPEAssembly, FILE_LOAD_POST_LOADLIBRARY)->GetAssembly();
- // Set up binder for CoreLib
- CoreLibBinder::AttachModule(m_pSystemAssembly->GetModule());
+ // Set up binder for CoreLib
+ CoreLibBinder::AttachModule(m_pSystemAssembly->GetModule());
- // Load Object
- g_pObjectClass = CoreLibBinder::GetClass(CLASS__OBJECT);
+ // Load Object
+ g_pObjectClass = CoreLibBinder::GetClass(CLASS__OBJECT);
- // Now that ObjectClass is loaded, we can set up
- // the system for finalizers. There is no point in deferring this, since we need
- // to know this before we allocate our first object.
- g_pObjectFinalizerMD = CoreLibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
+ // Now that ObjectClass is loaded, we can set up
+ // the system for finalizers. There is no point in deferring this, since we need
+ // to know this before we allocate our first object.
+ g_pObjectFinalizerMD = CoreLibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
- g_pCanonMethodTableClass = CoreLibBinder::GetClass(CLASS____CANON);
+ g_pCanonMethodTableClass = CoreLibBinder::GetClass(CLASS____CANON);
- // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
- // the other, because we have coded MethodTable::IsChildValueType
- // in such a way that it depends on this behaviour.
- // Load the ValueType class
- g_pValueTypeClass = CoreLibBinder::GetClass(CLASS__VALUE_TYPE);
+ // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
+ // the other, because we have coded MethodTable::IsChildValueType
+ // in such a way that it depends on this behaviour.
+ // Load the ValueType class
+ g_pValueTypeClass = CoreLibBinder::GetClass(CLASS__VALUE_TYPE);
- // Load the enum class
- g_pEnumClass = CoreLibBinder::GetClass(CLASS__ENUM);
- _ASSERTE(!g_pEnumClass->IsValueType());
+ // Load the enum class
+ g_pEnumClass = CoreLibBinder::GetClass(CLASS__ENUM);
+ _ASSERTE(!g_pEnumClass->IsValueType());
- // Load System.RuntimeType
- g_pRuntimeTypeClass = CoreLibBinder::GetClass(CLASS__CLASS);
- _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
+ // Load System.RuntimeType
+ g_pRuntimeTypeClass = CoreLibBinder::GetClass(CLASS__CLASS);
+ _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
- // Load Array class
- g_pArrayClass = CoreLibBinder::GetClass(CLASS__ARRAY);
+ // Load Array class
+ g_pArrayClass = CoreLibBinder::GetClass(CLASS__ARRAY);
- // Calling a method on IList<T> for an array requires redirection to a method on
- // the SZArrayHelper class. Retrieving such methods means calling
- // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
- // the corresponding method on SZArrayHelper. This basically results in a class
- // load due to a method call, which the debugger cannot handle, so we pre-load
- // the SZArrayHelper class here.
- g_pSZArrayHelperClass = CoreLibBinder::GetClass(CLASS__SZARRAYHELPER);
+ // Calling a method on IList<T> for an array requires redirection to a method on
+ // the SZArrayHelper class. Retrieving such methods means calling
+ // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
+ // the corresponding method on SZArrayHelper. This basically results in a class
+ // load due to a method call, which the debugger cannot handle, so we pre-load
+ // the SZArrayHelper class here.
+ g_pSZArrayHelperClass = CoreLibBinder::GetClass(CLASS__SZARRAYHELPER);
- // Load Nullable class
- g_pNullableClass = CoreLibBinder::GetClass(CLASS__NULLABLE);
+ // Load Nullable class
+ g_pNullableClass = CoreLibBinder::GetClass(CLASS__NULLABLE);
- // Load the Object array class.
- g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass));
+ // Load the Object array class.
+ g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass));
- // We have delayed allocation of CoreLib's static handles until we load the object class
- CoreLibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
+ // We have delayed allocation of CoreLib's static handles until we load the object class
+ CoreLibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
- // Boolean has to be loaded first to break cycle in IComparisonOperations and IEqualityOperators
- CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_BOOLEAN);
+ // Boolean has to be loaded first to break cycle in IComparisonOperations and IEqualityOperators
+ CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_BOOLEAN);
- // Int32 has to be loaded next to break cycle in IShiftOperators
- CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_I4);
+ // Int32 has to be loaded next to break cycle in IShiftOperators
+ CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_I4);
- // Make sure all primitive types are loaded
- for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
- CoreLibBinder::LoadPrimitiveType((CorElementType)et);
+ // Make sure all primitive types are loaded
+ for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
+ CoreLibBinder::LoadPrimitiveType((CorElementType)et);
- CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
- CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
+ CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
+ CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
- g_TypedReferenceMT = CoreLibBinder::GetClass(CLASS__TYPED_REFERENCE);
+ g_TypedReferenceMT = CoreLibBinder::GetClass(CLASS__TYPED_REFERENCE);
- // unfortunately, the following cannot be delay loaded since the jit
- // uses it to compute method attributes within a function that cannot
- // handle Complus exception and the following call goes through a path
- // where a complus exception can be thrown. It is unfortunate, because
- // we know that the delegate class and multidelegate class are always
- // guaranteed to be found.
- g_pDelegateClass = CoreLibBinder::GetClass(CLASS__DELEGATE);
- g_pMulticastDelegateClass = CoreLibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
+ // unfortunately, the following cannot be delay loaded since the jit
+ // uses it to compute method attributes within a function that cannot
+ // handle Complus exception and the following call goes through a path
+ // where a complus exception can be thrown. It is unfortunate, because
+ // we know that the delegate class and multidelegate class are always
+ // guaranteed to be found.
+ g_pDelegateClass = CoreLibBinder::GetClass(CLASS__DELEGATE);
+ g_pMulticastDelegateClass = CoreLibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
- // further loading of nonprimitive types may need casting support.
- // initialize cast cache here.
- CastCache::Initialize();
- ECall::PopulateManagedCastHelpers();
+ // further loading of nonprimitive types may need casting support.
+ // initialize cast cache here.
+ CastCache::Initialize();
+ ECall::PopulateManagedCastHelpers();
- // used by IsImplicitInterfaceOfSZArray
- CoreLibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
- CoreLibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
- CoreLibBinder::GetClass(CLASS__ILISTGENERIC);
- CoreLibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
- CoreLibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
+ // used by IsImplicitInterfaceOfSZArray
+ CoreLibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
+ CoreLibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
+ CoreLibBinder::GetClass(CLASS__ILISTGENERIC);
+ CoreLibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
+ CoreLibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
- // Load String
- g_pStringClass = CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
+ // Load String
+ g_pStringClass = CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
- ECall::PopulateManagedStringConstructors();
+ ECall::PopulateManagedStringConstructors();
- g_pExceptionClass = CoreLibBinder::GetClass(CLASS__EXCEPTION);
- g_pOutOfMemoryExceptionClass = CoreLibBinder::GetException(kOutOfMemoryException);
- g_pStackOverflowExceptionClass = CoreLibBinder::GetException(kStackOverflowException);
- g_pExecutionEngineExceptionClass = CoreLibBinder::GetException(kExecutionEngineException);
- g_pThreadAbortExceptionClass = CoreLibBinder::GetException(kThreadAbortException);
+ g_pExceptionClass = CoreLibBinder::GetClass(CLASS__EXCEPTION);
+ g_pOutOfMemoryExceptionClass = CoreLibBinder::GetException(kOutOfMemoryException);
+ g_pStackOverflowExceptionClass = CoreLibBinder::GetException(kStackOverflowException);
+ g_pExecutionEngineExceptionClass = CoreLibBinder::GetException(kExecutionEngineException);
+ g_pThreadAbortExceptionClass = CoreLibBinder::GetException(kThreadAbortException);
- g_pThreadClass = CoreLibBinder::GetClass(CLASS__THREAD);
+ g_pThreadClass = CoreLibBinder::GetClass(CLASS__THREAD);
- g_pWeakReferenceClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCE);
- g_pWeakReferenceOfTClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCEGENERIC);
+ g_pWeakReferenceClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCE);
+ g_pWeakReferenceOfTClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCEGENERIC);
-#ifdef FEATURE_COMINTEROP
- if (g_pConfig->IsBuiltInCOMSupported())
- {
- g_pBaseCOMObject = CoreLibBinder::GetClass(CLASS__COM_OBJECT);
- }
- else
- {
- g_pBaseCOMObject = NULL;
- }
-#endif
+ #ifdef FEATURE_COMINTEROP
+ if (g_pConfig->IsBuiltInCOMSupported())
+ {
+ g_pBaseCOMObject = CoreLibBinder::GetClass(CLASS__COM_OBJECT);
+ }
+ else
+ {
+ g_pBaseCOMObject = NULL;
+ }
+ #endif
- g_pIDynamicInterfaceCastableInterface = CoreLibBinder::GetClass(CLASS__IDYNAMICINTERFACECASTABLE);
+ g_pIDynamicInterfaceCastableInterface = CoreLibBinder::GetClass(CLASS__IDYNAMICINTERFACECASTABLE);
-#ifdef FEATURE_ICASTABLE
- g_pICastableInterface = CoreLibBinder::GetClass(CLASS__ICASTABLE);
-#endif // FEATURE_ICASTABLE
+ #ifdef FEATURE_ICASTABLE
+ g_pICastableInterface = CoreLibBinder::GetClass(CLASS__ICASTABLE);
+ #endif // FEATURE_ICASTABLE
- // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper.
- // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
- ECall::GetFCallImpl(CoreLibBinder::GetMethod(METHOD__MONITOR__ENTER));
+ // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper.
+ // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
+ ECall::GetFCallImpl(CoreLibBinder::GetMethod(METHOD__MONITOR__ENTER));
-#ifdef PROFILING_SUPPORTED
- // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
- // all base system classes are loaded. Profilers are not allowed to call any type-loading
- // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE. It is important that
- // all base system classes need to be loaded before profilers can trigger the type loading.
- g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
-#endif // PROFILING_SUPPORTED
+ #ifdef PROFILING_SUPPORTED
+ // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
+ // all base system classes are loaded. Profilers are not allowed to call any type-loading
+ // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE. It is important that
+ // all base system classes need to be loaded before profilers can trigger the type loading.
+ g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
+ #endif // PROFILING_SUPPORTED
-#if defined(_DEBUG)
- g_CoreLib.Check();
-#endif
+ // Perform any once-only SafeHandle initialization.
+ SafeHandle::Init();
+
+ #if defined(_DEBUG)
+ g_CoreLib.Check();
+ g_CoreLib.CheckExtended();
+ #endif // _DEBUG
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ LogErrorToHost("Failed to load System.Private.CoreLib.dll (error code 0x%08X)", ex->GetHR());
+ MAKE_UTF8PTR_FROMWIDE_NOTHROW(filePathUtf8, SystemDomain::System()->BaseLibrary())
+ if (filePathUtf8 != NULL)
+ {
+ LogErrorToHost("Path: %s", filePathUtf8);
+ }
+ SString err;
+ ex->GetMessage(err);
+ LogErrorToHost("Error message: %s", err.GetUTF8());
+ }
+ EX_END_HOOK;
}
#endif // !DACCESS_COMPILE
// requires write barriers to have been set up on x86, which happens as part
// of InitJITHelpers1.
hr = g_pGCHeap->Initialize();
+ if (FAILED(hr))
+ {
+ LogErrorToHost("GC heap initialization failed with error 0x%08X", hr);
+ }
+
IfFailGo(hr);
#ifdef FEATURE_PERFTRACING
StackSampler::Init();
#endif
- // Perform any once-only SafeHandle initialization.
- SafeHandle::Init();
-
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
// retrieve configured max size for the mini-metadata buffer (defaults to 64KB)
g_MiniMetaDataBuffMaxSize = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MiniMdBufferCapacity);
g_MiniMetaDataBuffMaxSize, MEM_COMMIT, PAGE_READWRITE);
#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
-
g_fEEStarted = TRUE;
g_EEStartupStatus = S_OK;
hr = S_OK;
{
SystemDomain::SystemModule()->ExpandAll();
}
-
- // Perform CoreLib consistency check if requested
- g_CoreLib.CheckExtended();
#endif // _DEBUG
}
EX_CATCH
{
+ hr = GET_EXCEPTION()->GetHR();
}
EX_END_CATCH(RethrowTerminalExceptionsWithInitCheck)
g_pFreeObjectMethodTable->SetComponentSize(1);
hr = GCHeapUtilities::LoadAndInitialize();
+
if (hr != S_OK)
{
+ LogErrorToHost("GC initialization failed with error 0x%08X", hr);
ThrowHR(hr);
}
CORINFO_OS getClrVmOs();
+#define LogJITInitializationError(...) \
+ LOG((LF_JIT, LL_FATALERROR, __VA_ARGS__)); \
+ LogErrorToHost(__VA_ARGS__);
+
// LoadAndInitializeJIT: load the JIT dll into the process, and initialize it (call the UtilCode initialization function,
// check the JIT-EE interface GUID, etc.)
//
if (pwzJitName == nullptr)
{
pJitLoadData->jld_hr = E_FAIL;
- LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: pwzJitName is null"));
+ LogJITInitializationError("LoadAndInitializeJIT: pwzJitName is null");
return;
}
}
else
{
- LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: invalid characters in %S\n", pwzJitName));
+ MAKE_UTF8PTR_FROMWIDE_NOTHROW(utf8JitName, pwzJitName);
+ LogJITInitializationError("LoadAndInitializeJIT: invalid characters in %s", utf8JitName);
}
}
+ MAKE_UTF8PTR_FROMWIDE_NOTHROW(utf8JitName, pwzJitName);
+
if (SUCCEEDED(hr))
{
pJitLoadData->jld_status = JIT_LOAD_STATUS_DONE_LOAD;
else
{
// Mismatched version ID. Fail the load.
- LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: mismatched JIT version identifier in %S\n", pwzJitName));
+ LogJITInitializationError("LoadAndInitializeJIT: mismatched JIT version identifier in %s", utf8JitName);
}
}
else
{
- LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: failed to get ICorJitCompiler in %S\n", pwzJitName));
+ LogJITInitializationError("LoadAndInitializeJIT: failed to get ICorJitCompiler in %s", utf8JitName);
}
}
else
{
- LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: failed to find 'getJit' entrypoint in %S\n", pwzJitName));
+ LogJITInitializationError("LoadAndInitializeJIT: failed to find 'getJit' entrypoint in %s", utf8JitName);
}
}
EX_CATCH
{
- LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: caught an exception trying to initialize %S\n", pwzJitName));
+ LogJITInitializationError("LoadAndInitializeJIT: LoadAndInitializeJIT: caught an exception trying to initialize %s", utf8JitName);
}
EX_END_CATCH(SwallowAllExceptions)
}
else
{
pJitLoadData->jld_hr = hr;
- LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: failed to load %S, hr=0x%08x\n", pwzJitName, hr));
+ LogJITInitializationError("LoadAndInitializeJIT: failed to load %s, hr=0x%08X", utf8JitName, hr);
}
}
#undef FPO_ON
#endif
+void LogErrorToHost(const char* format, ...);
+
#endif // !_common_h_
#include "dwreport.h"
#endif // !TARGET_UNIX
+#include "nativelibrary.h"
+
#ifndef DACCESS_COMPILE
#include <corehost/host_runtime_contract.h>
sAppPaths));
}
+#if defined(TARGET_UNIX) && !defined(CORECLR_EMBEDDED)
+ // Check if the current code is executing in the single file host or in libcoreclr.so. The libSystem.Native is linked
+ // into the single file host, so we need to check only when this code is in libcoreclr.so.
+ // Preload the libSystem.Native.so/dylib to detect possible problems with loading it early
+ EX_TRY
+ {
+ NativeLibrary::LoadLibraryByName(W("libSystem.Native"), SystemDomain::SystemAssembly(), FALSE, 0, TRUE);
+ }
+ EX_HOOK
+ {
+ Exception *ex = GET_EXCEPTION();
+ SString err;
+ ex->GetMessage(err);
+ LogErrorToHost("Error message: %s", err.GetUTF8());
+ }
+ EX_END_HOOK;
+#endif // TARGET_UNIX && !CORECLR_EMBEDDED
+
*pAppDomainID=DefaultADID;
m_fAppDomainCreated = TRUE;
{
ProfilerAddNewRegion(generation, rangeStart, rangeEnd, rangeEndReserved);
}
+
+void GCToEEInterface::LogErrorToHost(const char *message)
+{
+ ::LogErrorToHost("GC: %s", message);
+}
uint32_t GetCurrentProcessCpuCount();
void DiagAddNewRegion(int generation, BYTE * rangeStart, BYTE * rangeEnd, BYTE * rangeEndReserved);
+
+ void LogErrorToHost(const char *message);
};
} // namespace standalone
#pragma comment(linker, "/export:coreclr_execute_assembly=_coreclr_execute_assembly@24")
#pragma comment(linker, "/export:coreclr_shutdown_2=_coreclr_shutdown_2@12")
#pragma comment(linker, "/export:coreclr_create_delegate=_coreclr_create_delegate@24")
+#pragma comment(linker, "/export:coreclr_set_error_writer=_coreclr_set_error_writer@4")
#undef MONO_API
#define MONO_API MONO_EXTERN_C
#endif
+//
+// Type of the callback function that can be set by the coreclr_set_error_writer
+//
+typedef void (*coreclr_error_writer_callback_fn) (const char *message);
+
MONO_API int STDAPICALLTYPE coreclr_initialize (const char* exePath, const char* appDomainFriendlyName,
int propertyCount, const char** propertyKeys, const char** propertyValues,
void** hostHandle, unsigned int* domainId);
const char* entryPointAssemblyName, const char* entryPointTypeName, const char* entryPointMethodName,
void** delegate);
+MONO_API int STDAPICALLTYPE coreclr_set_error_writer(coreclr_error_writer_callback_fn error_writer);
+
//
// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
//
{
return monovm_create_delegate (entryPointAssemblyName, entryPointTypeName, entryPointMethodName, delegate);
}
+
+//
+// Set callback for writing error logging
+//
+// Parameters:
+// errorWriter - callback that will be called for each line of the error info
+// - passing in NULL removes a callback that was previously set
+//
+// Returns:
+// S_OK
+//
+int STDAPICALLTYPE coreclr_set_error_writer(coreclr_error_writer_callback_fn error_writer)
+{
+ return 0; // S_OK
+}
using host_handle_t = void*;
+typedef void (*coreclr_error_writer_callback_fn)(const char* line);
+
// Prototype of the coreclr_initialize function from coreclr.dll
using coreclr_initialize_fn = pal::hresult_t(STDMETHODCALLTYPE*)(
const char* exePath,
host_handle_t* hostHandle,
unsigned int* domainId);
+// Prototype of the coreclr_set_error_writer function from coreclr.dll
+using coreclr_set_error_writer_fn = pal::hresult_t(STDMETHODCALLTYPE*)(
+ coreclr_error_writer_callback_fn callBack);
+
// Prototype of the coreclr_shutdown function from coreclr.dll
using coreclr_shutdown_fn = pal::hresult_t(STDMETHODCALLTYPE*)(
host_handle_t hostHandle,
struct coreclr_resolver_contract_t
{
pal::dll_t coreclr;
+ coreclr_set_error_writer_fn coreclr_set_error_writer;
coreclr_shutdown_fn coreclr_shutdown;
coreclr_initialize_fn coreclr_initialize;
coreclr_execute_assembly_fn coreclr_execute_assembly;
coreclr_resolver_t::resolve_coreclr(libcoreclr_path, coreclr_contract);
return true;
}
+
+ void log_error(const char* line)
+ {
+ pal::string_t lineStr;
+ pal::clr_palstring(line, &lineStr);
+ trace::error(_X("%s"), lineStr.c_str());
+ }
}
pal::hresult_t coreclr_t::create(
};
properties.enumerate(callback);
+ // Can't use propagate_error_writer_t here because of the difference in encoding on Windows
+ // coreclr error writer always gets UTF8 string, but error writers in hostfxr/hostpolicy will use UTF16 on Windows
+ // and UTF8 everywhere else.
+ if (coreclr_contract.coreclr_set_error_writer != nullptr)
+ {
+ coreclr_contract.coreclr_set_error_writer(log_error);
+ }
+
pal::hresult_t hr;
hr = coreclr_contract.coreclr_initialize(
exe_path,
&host_handle,
&domain_id);
+ if (coreclr_contract.coreclr_set_error_writer != nullptr)
+ {
+ coreclr_contract.coreclr_set_error_writer(nullptr);
+ }
+
if (!SUCCEEDED(hr))
return hr;
}
coreclr_resolver_contract.coreclr_initialize = reinterpret_cast<coreclr_initialize_fn>(pal::get_symbol(coreclr_resolver_contract.coreclr, "coreclr_initialize"));
+ coreclr_resolver_contract.coreclr_set_error_writer = reinterpret_cast<coreclr_set_error_writer_fn>(pal::get_symbol(coreclr_resolver_contract.coreclr, "coreclr_set_error_writer"));
coreclr_resolver_contract.coreclr_shutdown = reinterpret_cast<coreclr_shutdown_fn>(pal::get_symbol(coreclr_resolver_contract.coreclr, "coreclr_shutdown_2"));
coreclr_resolver_contract.coreclr_execute_assembly = reinterpret_cast<coreclr_execute_assembly_fn>(pal::get_symbol(coreclr_resolver_contract.coreclr, "coreclr_execute_assembly"));
coreclr_resolver_contract.coreclr_create_delegate = reinterpret_cast<coreclr_create_delegate_fn>(pal::get_symbol(coreclr_resolver_contract.coreclr, "coreclr_create_delegate"));
+ // Only the coreclr_set_error_writer is optional
assert(coreclr_resolver_contract.coreclr_initialize != nullptr
&& coreclr_resolver_contract.coreclr_shutdown != nullptr
&& coreclr_resolver_contract.coreclr_execute_assembly != nullptr