Skip to content

Commit

Permalink
Add runtime module address to SpecialDiagInfo block in createdump (#9…
Browse files Browse the repository at this point in the history
…5816)

* Add runtime module address to SpecialDiagInfo block in createdump

Fix missing DotNetRuntimeDebugHeader export:

  Add ILC options:
    --export-dynamic-symbol - Add dynamic export symbol to export file. Used to add DotNetRuntimeDebugHeader export.
    --export-unmanaged-entrypoints - controls whether the exported method definitions are exported

  Change Native AOT build integration to always pass an export file to ILC and linker.

* Bump the Native AOT data contract sizes
  • Loading branch information
mikem8361 committed Dec 12, 2023
1 parent f1d5cea commit f9529fd
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 22 deletions.
4 changes: 4 additions & 0 deletions src/coreclr/debug/createdump/crashinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) :
Expand All @@ -30,6 +33,7 @@ CrashInfo::CrashInfo(const CreateDumpOptions& options) :
m_enumMemoryPagesAdded(0)
{
g_crashInfo = this;
m_runtimeBaseAddress = 0;
#ifdef __APPLE__
m_task = 0;
#else
Expand Down
20 changes: 20 additions & 0 deletions src/coreclr/debug/createdump/crashinfomac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include "createdump.h"

extern uint8_t g_debugHeaderCookie[4];

int g_readProcessMemoryResult = KERN_SUCCESS;

bool
Expand Down Expand Up @@ -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();
Expand Down
22 changes: 22 additions & 0 deletions src/coreclr/debug/createdump/crashinfounix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#endif

extern CrashInfo* g_crashInfo;
extern uint8_t g_debugHeaderCookie[4];

int g_readProcessMemoryErrno = 0;

Expand Down Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/debug/createdump/dumpwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions src/coreclr/debug/createdump/specialdiaginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,4 +31,5 @@ struct SpecialDiagInfoHeader
char Signature[16];
int32_t Version;
uint64_t ExceptionRecordAddress;
uint64_t RuntimeBaseAddress;
};
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<NativeObject>$(NativeIntermediateOutputPath)$(TargetName)$(NativeObjectExt)</NativeObject>
<NativeBinary>$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)</NativeBinary>
<IlcExportUnmanagedEntrypoints Condition="'$(IlcExportUnmanagedEntrypoints)' == '' and '$(NativeLib)' == 'Shared'">true</IlcExportUnmanagedEntrypoints>
<ExportsFile Condition="$(IlcExportUnmanagedEntrypoints) == 'true' and $(ExportsFile) == ''">$(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)</ExportsFile>
<ExportsFile Condition="$(ExportsFile) == ''">$(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)</ExportsFile>

<IlcCompileOutput>$(NativeObject)</IlcCompileOutput>

Expand Down Expand Up @@ -240,7 +240,10 @@ The .NET Foundation licenses this file to you under the MIT license.
<IlcArg Include="@(TrimmerRootDescriptor->'--descriptor:%(FullPath)')" />
<IlcArg Condition="'$(NativeLib)' != ''" Include="--nativelib" />
<IlcArg Condition="'$(CustomNativeMain)' == 'true'" Include="--splitinit" />
<IlcArg Condition="$(ExportsFile) != ''" Include="--exportsfile:$(ExportsFile)" />
<IlcArg Condition="'$(ExportsFile)' != ''" Include="--exportsfile:$(ExportsFile)" />
<IlcArg Condition="'$(_targetOS)' == 'win' and '$(DebuggerSupport)' != 'false'" Include="--export-dynamic-symbol:DotNetRuntimeDebugHeader,DATA" />
<IlcArg Condition="'$(_targetOS)' != 'win' and '$(DebuggerSupport)' != 'false'" Include="--export-dynamic-symbol:DotNetRuntimeDebugHeader" />
<IlcArg Condition="'$(IlcExportUnmanagedEntrypoints)' == 'true'" Include="--export-unmanaged-entrypoints" />
<IlcArg Include="@(AutoInitializedAssemblies->'--initassembly:%(Identity)')" />
<IlcArg Include="@(DirectPInvoke->'--directpinvoke:%(Identity)')" />
<IlcArg Include="@(DirectPInvokeList->'--directpinvokelist:%(Identity)')" />
Expand Down Expand Up @@ -329,12 +332,11 @@ The .NET Foundation licenses this file to you under the MIT license.
<CustomLinkerArg Include="-o &quot;$(NativeBinary)&quot;" Condition="'$(_targetOS)' != 'win'" />
<CustomLinkerArg Include="/OUT:&quot;$(NativeBinary)&quot;" Condition="'$(_targetOS)' == 'win'" />
<CustomLinkerArg Include="/DEF:&quot;$(ExportsFile)&quot;" Condition="'$(_targetOS)' == 'win' and $(ExportsFile) != ''" />
<CustomLinkerArg Include="/EXPORT:DotNetRuntimeDebugHeader,DATA" Condition="'$(_targetOS)' == 'win' and '$(DebuggerSupport)' != 'false'" />
<CustomLinkerArg Include="/LIBPATH:&quot;%(AdditionalNativeLibraryDirectories.Identity)&quot;" Condition="'$(_targetOS)' == 'win' and '@(AdditionalNativeLibraryDirectories->Count())' &gt; 0" />
<CustomLinkerArg Include="-exported_symbols_list &quot;$(ExportsFile)&quot;" Condition="'$(_IsApplePlatform)' == 'true' and '$(ExportsFile)' != ''" />
<CustomLinkerArg Include="-exported_symbols_list /dev/null" Condition="'$(OutputType)' == 'exe' and '$(_IsApplePlatform)' == 'true' and '$(ExportsFile)' == ''" />
<CustomLinkerArg Include="-Wl,--version-script=$(ExportsFile)" Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true' and $(ExportsFile) != ''" />
<CustomLinkerArg Include="-Wl,--export-dynamic" Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true' and '$(IlcExportUnmanagedEntrypoints)' == 'true' and '$(NativeLib)' == ''" />
<CustomLinkerArg Include="-Wl,--version-script=$(ExportsFile)" Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true' and '$(ExportsFile)' != ''" />
<CustomLinkerArg Include="-Wl,--export-dynamic" Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true' and '$(ExportsFile)' != ''" />
<CustomLinkerArg Include="@(LinkerArg)" />
</ItemGroup>
<ItemGroup Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true'">
Expand Down
12 changes: 8 additions & 4 deletions src/coreclr/nativeaot/Runtime/DebugHeader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -108,14 +108,18 @@ struct DotNetRuntimeDebugHeader
};

extern "C" struct DotNetRuntimeDebugHeader DotNetRuntimeDebugHeader;

#ifdef HOST_UNIX
__attribute__ ((visibility ("default")))
#endif
struct DotNetRuntimeDebugHeader DotNetRuntimeDebugHeader = {};

#define MAKE_DEBUG_ENTRY(TypeName, FieldName, Value) \
do \
{ \
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))
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ namespace ILCompiler
{
public class ExportsFileWriter
{
private string _exportsFile;
private List<EcmaMethod> _methods;
private TypeSystemContext _context;
private readonly string _exportsFile;
private readonly IEnumerable<string> _exportSymbols;
private readonly List<EcmaMethod> _methods;
private readonly TypeSystemContext _context;

public ExportsFileWriter(TypeSystemContext context, string exportsFile)
public ExportsFileWriter(TypeSystemContext context, string exportsFile, IEnumerable<string> exportSymbols)
{
_exportsFile = exportsFile;
_exportSymbols = exportSymbols;
_context = context;
_methods = new List<EcmaMethod>();
}
Expand All @@ -34,18 +36,24 @@ 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()}");
}
else
{
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: *;");
Expand Down
8 changes: 7 additions & 1 deletion src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ internal sealed class ILCompilerRootCommand : CliRootCommand
public CliOption<bool> SplitExeInitialization { get; } =
new("--splitinit") { Description = "Split initialization of an executable between the library entrypoint and a main entrypoint" };
public CliOption<string> ExportsFile { get; } =
new("--exportsfile") { Description = "File to write exported method definitions" };
new("--exportsfile") { Description = "File to write exported symbol and method definitions" };
public CliOption<bool> ExportUnmanagedEntryPoints { get; } =
new("--export-unmanaged-entrypoints") { Description = "Controls whether the named UnmanagedCallersOnly methods are exported" };
public CliOption<string[]> ExportDynamicSymbols { get; } =
new("--export-dynamic-symbol") { Description = "Add dynamic export symbol to exports file" };
public CliOption<string> DgmlLogFileName { get; } =
new("--dgmllog") { Description = "Save result of dependency analysis as DGML" };
public CliOption<bool> GenerateFullDgmlLog { get; } =
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 8 additions & 4 deletions src/coreclr/tools/aot/ILCompiler/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit f9529fd

Please sign in to comment.