diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp
index 9b4377c7be7ed..044a731eb8684 100644
--- a/src/coreclr/debug/createdump/crashinfo.cpp
+++ b/src/coreclr/debug/createdump/crashinfo.cpp
@@ -9,6 +9,9 @@ typedef HINSTANCE (PALAPI_NOEXPORT *PFN_REGISTER_MODULE)(LPCSTR); /* u
// This is for the PAL_VirtualUnwindOutOfProc read memory adapter.
CrashInfo* g_crashInfo;
+// This is the NativeAOT DotNetRuntimeDebugHeader signature
+uint8_t g_debugHeaderCookie[4] = { 0x44, 0x4E, 0x44, 0x48 };
+
static bool ModuleInfoCompare(const ModuleInfo* lhs, const ModuleInfo* rhs) { return lhs->BaseAddress() < rhs->BaseAddress(); }
CrashInfo::CrashInfo(const CreateDumpOptions& options) :
@@ -30,6 +33,7 @@ CrashInfo::CrashInfo(const CreateDumpOptions& options) :
m_enumMemoryPagesAdded(0)
{
g_crashInfo = this;
+ m_runtimeBaseAddress = 0;
#ifdef __APPLE__
m_task = 0;
#else
diff --git a/src/coreclr/debug/createdump/crashinfomac.cpp b/src/coreclr/debug/createdump/crashinfomac.cpp
index 90a31f106d684..89c71c9e586c8 100644
--- a/src/coreclr/debug/createdump/crashinfomac.cpp
+++ b/src/coreclr/debug/createdump/crashinfomac.cpp
@@ -3,6 +3,8 @@
#include "createdump.h"
+extern uint8_t g_debugHeaderCookie[4];
+
int g_readProcessMemoryResult = KERN_SUCCESS;
bool
@@ -263,6 +265,24 @@ void CrashInfo::VisitModule(MachOModule& module)
}
}
}
+ else if (m_appModel == AppModelType::NativeAOT)
+ {
+ uint64_t symbolOffset;
+ if (module.TryLookupSymbol("DotNetRuntimeDebugHeader", &symbolOffset))
+ {
+ m_coreclrPath = GetDirectory(module.Name());
+ m_runtimeBaseAddress = module.BaseAddress();
+
+ uint8_t cookie[sizeof(g_debugHeaderCookie)];
+ if (ReadMemory((void*)(module.BaseAddress() + symbolOffset), cookie, sizeof(cookie)))
+ {
+ if (memcmp(cookie, g_debugHeaderCookie, sizeof(g_debugHeaderCookie)) == 0)
+ {
+ TRACE("Found valid NativeAOT runtime module\n");
+ }
+ }
+ }
+ }
}
// VisitSegment is called for each segment of the module
module.EnumerateSegments();
diff --git a/src/coreclr/debug/createdump/crashinfounix.cpp b/src/coreclr/debug/createdump/crashinfounix.cpp
index 583dad75a17ef..4d39ade7fda90 100644
--- a/src/coreclr/debug/createdump/crashinfounix.cpp
+++ b/src/coreclr/debug/createdump/crashinfounix.cpp
@@ -8,6 +8,7 @@
#endif
extern CrashInfo* g_crashInfo;
+extern uint8_t g_debugHeaderCookie[4];
int g_readProcessMemoryErrno = 0;
@@ -383,6 +384,27 @@ CrashInfo::VisitModule(uint64_t baseAddress, std::string& moduleName)
}
}
}
+ else if (m_appModel == AppModelType::NativeAOT)
+ {
+ if (PopulateForSymbolLookup(baseAddress))
+ {
+ uint64_t symbolOffset;
+ if (TryLookupSymbol("DotNetRuntimeDebugHeader", &symbolOffset))
+ {
+ m_coreclrPath = GetDirectory(moduleName);
+ m_runtimeBaseAddress = baseAddress;
+
+ uint8_t cookie[sizeof(g_debugHeaderCookie)];
+ if (ReadMemory((void*)(baseAddress + symbolOffset), cookie, sizeof(cookie)))
+ {
+ if (memcmp(cookie, g_debugHeaderCookie, sizeof(g_debugHeaderCookie)) == 0)
+ {
+ TRACE("Found valid NativeAOT runtime module\n");
+ }
+ }
+ }
+ }
+ }
}
EnumerateProgramHeaders(baseAddress);
}
diff --git a/src/coreclr/debug/createdump/dumpwriter.cpp b/src/coreclr/debug/createdump/dumpwriter.cpp
index 5153ba790154f..0e39b52b3a7d4 100644
--- a/src/coreclr/debug/createdump/dumpwriter.cpp
+++ b/src/coreclr/debug/createdump/dumpwriter.cpp
@@ -39,7 +39,8 @@ DumpWriter::WriteDiagInfo(size_t size)
SpecialDiagInfoHeader header = {
{SPECIAL_DIAGINFO_SIGNATURE},
SPECIAL_DIAGINFO_VERSION,
- m_crashInfo.ExceptionRecord()
+ m_crashInfo.ExceptionRecord(),
+ m_crashInfo.RuntimeBaseAddress()
};
if (!WriteData(&header, sizeof(header))) {
return false;
diff --git a/src/coreclr/debug/createdump/specialdiaginfo.h b/src/coreclr/debug/createdump/specialdiaginfo.h
index a857129c9c91f..84f79f00a160d 100644
--- a/src/coreclr/debug/createdump/specialdiaginfo.h
+++ b/src/coreclr/debug/createdump/specialdiaginfo.h
@@ -8,11 +8,11 @@
// ******************************************************************************
// This is a special memory region added to ELF and MachO dumps that contains extra diagnostics
-// information like the exception record for a crash for a NativeAOT app. The exception record
-// contains the pointer to the JSON formatted crash info.
+// information like the exception record address for a NativeAOT app crash or the runtime module
+// base address. The exception record contains the pointer to the JSON formatted crash info.
#define SPECIAL_DIAGINFO_SIGNATURE "DIAGINFOHEADER"
-#define SPECIAL_DIAGINFO_VERSION 1
+#define SPECIAL_DIAGINFO_VERSION 2
#ifdef __APPLE__
const uint64_t SpecialDiagInfoAddress = 0x7fffffff10000000;
@@ -31,4 +31,5 @@ struct SpecialDiagInfoHeader
char Signature[16];
int32_t Version;
uint64_t ExceptionRecordAddress;
+ uint64_t RuntimeBaseAddress;
};
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
index ba1e1480ed8e6..c496ce5b6699e 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -81,7 +81,7 @@ The .NET Foundation licenses this file to you under the MIT license.
$(NativeIntermediateOutputPath)$(TargetName)$(NativeObjectExt)
$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)
true
- $(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)
+ $(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)
$(NativeObject)
@@ -240,7 +240,10 @@ The .NET Foundation licenses this file to you under the MIT license.
-
+
+
+
+
@@ -329,12 +332,11 @@ The .NET Foundation licenses this file to you under the MIT license.
-
-
-
+
+
diff --git a/src/coreclr/nativeaot/Runtime/DebugHeader.cpp b/src/coreclr/nativeaot/Runtime/DebugHeader.cpp
index b01339f812031..d6f34b10708e5 100644
--- a/src/coreclr/nativeaot/Runtime/DebugHeader.cpp
+++ b/src/coreclr/nativeaot/Runtime/DebugHeader.cpp
@@ -36,12 +36,12 @@ struct GlobalValueEntry
// This size should be one bigger than the number of entries since a null entry
// signifies the end of the array.
-static constexpr size_t DebugTypeEntriesArraySize = 96;
+static constexpr size_t DebugTypeEntriesArraySize = 100;
static DebugTypeEntry s_DebugEntries[DebugTypeEntriesArraySize];
// This size should be one bigger than the number of entries since a null entry
// signifies the end of the array.
-static constexpr size_t GlobalEntriesArraySize = 6;
+static constexpr size_t GlobalEntriesArraySize = 8;
static GlobalValueEntry s_GlobalEntries[GlobalEntriesArraySize];
// This structure is part of a in-memory serialization format that is used by diagnostic tools to
@@ -108,6 +108,10 @@ struct DotNetRuntimeDebugHeader
};
extern "C" struct DotNetRuntimeDebugHeader DotNetRuntimeDebugHeader;
+
+#ifdef HOST_UNIX
+__attribute__ ((visibility ("default")))
+#endif
struct DotNetRuntimeDebugHeader DotNetRuntimeDebugHeader = {};
#define MAKE_DEBUG_ENTRY(TypeName, FieldName, Value) \
@@ -115,7 +119,7 @@ struct DotNetRuntimeDebugHeader DotNetRuntimeDebugHeader = {};
{ \
s_DebugEntries[currentDebugPos] = { #TypeName, #FieldName, Value, 0 }; \
++currentDebugPos; \
- ASSERT(currentDebugPos <= DebugTypeEntriesArraySize); \
+ ASSERT(currentDebugPos < DebugTypeEntriesArraySize); \
} while(0)
#define MAKE_DEBUG_FIELD_ENTRY(TypeName, FieldName) MAKE_DEBUG_ENTRY(TypeName, FieldName, offsetof(TypeName, FieldName))
@@ -129,7 +133,7 @@ struct DotNetRuntimeDebugHeader DotNetRuntimeDebugHeader = {};
{ \
s_GlobalEntries[currentGlobalPos] = { #Name, Name }; \
++currentGlobalPos; \
- ASSERT(currentGlobalPos <= GlobalEntriesArraySize); \
+ ASSERT(currentGlobalPos < GlobalEntriesArraySize); \
} while(0) \
extern "C" void PopulateDebugHeaders()
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs
index 9937ecacc986c..7f1a4e2b51de4 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs
@@ -12,13 +12,15 @@ namespace ILCompiler
{
public class ExportsFileWriter
{
- private string _exportsFile;
- private List _methods;
- private TypeSystemContext _context;
+ private readonly string _exportsFile;
+ private readonly IEnumerable _exportSymbols;
+ private readonly List _methods;
+ private readonly TypeSystemContext _context;
- public ExportsFileWriter(TypeSystemContext context, string exportsFile)
+ public ExportsFileWriter(TypeSystemContext context, string exportsFile, IEnumerable exportSymbols)
{
_exportsFile = exportsFile;
+ _exportSymbols = exportSymbols;
_context = context;
_methods = new List();
}
@@ -34,11 +36,15 @@ public void EmitExportedMethods()
if (_context.Target.IsWindows)
{
streamWriter.WriteLine("EXPORTS");
+ foreach (string symbol in _exportSymbols)
+ streamWriter.WriteLine($" {symbol.Replace(',', ' ')}");
foreach (var method in _methods)
streamWriter.WriteLine($" {method.GetUnmanagedCallersOnlyExportName()}");
}
else if(_context.Target.IsOSXLike)
{
+ foreach (string symbol in _exportSymbols)
+ streamWriter.WriteLine($"_{symbol}");
foreach (var method in _methods)
streamWriter.WriteLine($"_{method.GetUnmanagedCallersOnlyExportName()}");
}
@@ -46,6 +52,8 @@ public void EmitExportedMethods()
{
streamWriter.WriteLine("V1.0 {");
streamWriter.WriteLine(" global: _init; _fini;");
+ foreach (string symbol in _exportSymbols)
+ streamWriter.WriteLine($" {symbol};");
foreach (var method in _methods)
streamWriter.WriteLine($" {method.GetUnmanagedCallersOnlyExportName()};");
streamWriter.WriteLine(" local: *;");
diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs b/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
index 4524f7a854bc5..d096cc9bbeb12 100644
--- a/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
+++ b/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
@@ -38,7 +38,11 @@ internal sealed class ILCompilerRootCommand : CliRootCommand
public CliOption SplitExeInitialization { get; } =
new("--splitinit") { Description = "Split initialization of an executable between the library entrypoint and a main entrypoint" };
public CliOption ExportsFile { get; } =
- new("--exportsfile") { Description = "File to write exported method definitions" };
+ new("--exportsfile") { Description = "File to write exported symbol and method definitions" };
+ public CliOption ExportUnmanagedEntryPoints { get; } =
+ new("--export-unmanaged-entrypoints") { Description = "Controls whether the named UnmanagedCallersOnly methods are exported" };
+ public CliOption ExportDynamicSymbols { get; } =
+ new("--export-dynamic-symbol") { Description = "Add dynamic export symbol to exports file" };
public CliOption DgmlLogFileName { get; } =
new("--dgmllog") { Description = "Save result of dependency analysis as DGML" };
public CliOption GenerateFullDgmlLog { get; } =
@@ -176,6 +180,8 @@ public ILCompilerRootCommand(string[] args) : base(".NET Native IL Compiler")
Options.Add(NativeLib);
Options.Add(SplitExeInitialization);
Options.Add(ExportsFile);
+ Options.Add(ExportDynamicSymbols);
+ Options.Add(ExportUnmanagedEntryPoints);
Options.Add(DgmlLogFileName);
Options.Add(GenerateFullDgmlLog);
Options.Add(ScanDgmlLogFileName);
diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs
index 66df76365d8d2..0ff5cd87b5ffe 100644
--- a/src/coreclr/tools/aot/ILCompiler/Program.cs
+++ b/src/coreclr/tools/aot/ILCompiler/Program.cs
@@ -574,11 +574,15 @@ void RunScanner()
string exportsFile = Get(_command.ExportsFile);
if (exportsFile != null)
{
- ExportsFileWriter defFileWriter = new ExportsFileWriter(typeSystemContext, exportsFile);
- foreach (var compilationRoot in compilationRoots)
+ ExportsFileWriter defFileWriter = new ExportsFileWriter(typeSystemContext, exportsFile, Get(_command.ExportDynamicSymbols));
+
+ if (Get(_command.ExportUnmanagedEntryPoints))
{
- if (compilationRoot is UnmanagedEntryPointsRootProvider provider)
- defFileWriter.AddExportedMethods(provider.ExportedMethods);
+ foreach (var compilationRoot in compilationRoots)
+ {
+ if (compilationRoot is UnmanagedEntryPointsRootProvider provider)
+ defFileWriter.AddExportedMethods(provider.ExportedMethods);
+ }
}
defFileWriter.EmitExportedMethods();