Add linked createdump support for NativeAOT executables - #132572
Conversation
Implement a minimal ELF core dump writer in pure C for NativeAOT. This provides crash dump generation without depending on the C++ runtime, which NativeAOT cannot use. The implementation reads process state via /proc and ptrace, then writes a standard ELF core dump containing: - NT_PRPSINFO, NT_AUXV, NT_FILE notes - Per-thread NT_PRSTATUS, NT_FPREGSET, NT_SIGINFO notes - All readable memory regions (PT_LOAD segments) Supports x86_64 and aarch64. Builds as enabled/disabled static library variants following the established NativeAOT pattern (EventPipe, VxSort). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Integrate the linked-in createdump library into the NativeAOT build and runtime startup: - Bootstrap main.cpp: Check for GUID sentinel argument before runtime initialization. When detected, redirect into the dump writer instead of normal startup. - PalCreateDump.cpp: When the enabled library is linked, use self-restart mode (fork + re-exec self with sentinel) instead of looking for an external createdump binary. Falls back to external binary if self-path resolution fails. - MSBuild: Select enabled/disabled variant via CreatedumpSupportName property, tied to EventSourceSupport on Linux. - SDK packaging: Register both library variants in the platform manifest. - Smoke test: Self-invoking test that crashes a child process and validates the generated ELF core dump. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add an optimized dump mode that excludes shared library code/rodata, reducing dump size from ~75MB to ~32MB for typical NativeAOT apps while preserving full GDB debugging capability. The new GetDumpSize() function determines per-region inclusion: - Full mode (--full / DbgMiniDumpType=4): all readable memory - Heap mode (default): writable memory, anonymous regions, main executable (including RELRO pages with r_debug for GDB shared library resolution), and the first page of each shared library ELF header. Shared library .text/.rodata is excluded since debuggers load it from disk via NT_FILE. Update the smoke test to exercise the heap dump path (type 2) and verify the linked-in createdump path is used via the [createdump] stderr marker. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Limit linked createdump dispatch to explicitly opted-in Linux NativeAOT executables while preserving external-createdump behavior for unsupported requests and output shapes. Correct ELF capture, mapping selection, error handling, and security checks, and strengthen end-to-end validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 49628d5c-675b-40b0-96d5-9ea25a1ea213
|
Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib |
There was a problem hiding this comment.
Pull request overview
Adds “linked-in createdump” support for Linux NativeAOT executables by introducing a minimal in-process (self re-exec) createdump implementation, wiring it into the NativeAOT bootstrap / PalCreateDump dispatch, and validating it with a new NativeAOT smoke test.
Changes:
- Add a new
nativeaot-createdump-enabledstatic library (Linux, supported arch) containing a minimal/proc+ptracereader and ELF core writer, plus a disabled stub variant. - Update NativeAOT bootstrap +
PalCreateDumpto support a self-reexec dispatch using a GUID sentinel and/proc/self/exe(while retaining external-helper fallback paths). - Add a Linux NativeAOT smoke test and integrate the new libraries into build/packaging plumbing.
Show a summary per file
| File | Description |
|---|---|
| src/tests/nativeaot/SmokeTests/CreatedumpLinkedIn/CreatedumpLinkedIn.csproj | New Linux NativeAOT smoke-test project enabling CreatedumpSupport. |
| src/tests/nativeaot/SmokeTests/CreatedumpLinkedIn/CreatedumpLinkedIn.cs | End-to-end validation for linked dump generation + external-helper fallback behavior. |
| src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props | Adds NativeAOT createdump static libs to the platform manifest entries. |
| src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp | Adds self-reexec mode selection and sentinel insertion for linked createdump dispatch. |
| src/coreclr/nativeaot/Runtime/createdump/process_reader.h | New minimal process snapshot types/APIs for dump generation. |
| src/coreclr/nativeaot/Runtime/createdump/process_reader.c | Implements /proc parsing + ptrace thread attach/register capture. |
| src/coreclr/nativeaot/Runtime/createdump/nativeaot_createdump_main.c | New linked createdump entrypoint invoked via sentinel re-exec. |
| src/coreclr/nativeaot/Runtime/createdump/elf_dump_writer.h | Declares minimal ELF core dump writer API. |
| src/coreclr/nativeaot/Runtime/createdump/elf_dump_writer.c | Implements ELF core file construction, notes, and filtered memory emission. |
| src/coreclr/nativeaot/Runtime/createdump/createdump_sentinel.h | Defines the GUID sentinel argument for createdump self-reexec dispatch. |
| src/coreclr/nativeaot/Runtime/createdump/createdump_disabled.c | Disabled stub implementation for unsupported/disabled configurations. |
| src/coreclr/nativeaot/Runtime/createdump/CMakeLists.txt | Adds build/install rules for enabled/disabled createdump libraries. |
| src/coreclr/nativeaot/Runtime/CMakeLists.txt | Adds the createdump subdirectory to the NativeAOT runtime build (non-Windows). |
| src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets | Adds CreatedumpSupportName selection and links the chosen library into NativeAOT Unix builds. |
| src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets | Introduces CreatedumpSupport MSBuild property defaulting to false. |
| src/coreclr/nativeaot/Bootstrap/main.cpp | Adds sentinel detection/dispatch to nativeaot_createdump_main before runtime initialization. |
Review details
Suppressed comments (2)
src/coreclr/nativeaot/Runtime/createdump/elf_dump_writer.c:187
CalculateNotesSizeaccumulates note sizes with unchecked arithmetic (includingauxv.count * sizeof(Elf64_auxv_t)and repeatedtotal += ...). If this overflows,notesSizecan become too small and the file layout computations inWriteElfCoreDumpcan produce overlapping sections.
// NT_PRPSINFO
total += NoteSize(CORE_NOTE_NAME_SIZE, sizeof(struct elf_prpsinfo));
// NT_AUXV
total += NoteSize(CORE_NOTE_NAME_SIZE, info->auxv.count * sizeof(Elf64_auxv_t));
src/coreclr/nativeaot/Runtime/createdump/elf_dump_writer.c:199
- Per-thread note size accumulation in
CalculateNotesSizealso needs overflow checks. Without them, a process with many threads could overflowtotaland causenotesSizeto under-report.
// NT_PRSTATUS
total += NoteSize(CORE_NOTE_NAME_SIZE, sizeof(struct elf_prstatus));
// NT_FPREGSET
total += NoteSize(CORE_NOTE_NAME_SIZE, sizeof(fp_regs_t));
- Files reviewed: 16/16 changed files
- Comments generated: 4
- Review effort level: Lite
| #include <unistd.h> | ||
| #define __STDC_FORMAT_MACROS | ||
| #include <inttypes.h> |
| static size_t NtFileDataSize(const ProcessInfo* info) | ||
| { | ||
| // Header: count (8 bytes) + page_size (8 bytes) | ||
| size_t size = 2 * sizeof(uint64_t); | ||
|
|
||
| // Per-file entry: start (8) + end (8) + offset (8) | ||
| size_t fileCount = CountFileRegions(info); | ||
| size += fileCount * 3 * sizeof(uint64_t); | ||
|
|
||
| // File name strings (null-terminated) | ||
| for (size_t i = 0; i < info->regions.count; i++) | ||
| { | ||
| if (info->regions.items[i].fileName[0] != '\0' && | ||
| info->regions.items[i].fileName[0] != '[') | ||
| { | ||
| size += strlen(info->regions.items[i].fileName) + 1; | ||
| } | ||
| } | ||
|
|
||
| return size; | ||
| } |
|
|
||
| # Enabled variant: full ELF core dump writer (Linux only). | ||
| # macOS support requires Mach-O dump format and Mach APIs — deferred to future work. | ||
| if(CLR_CMAKE_TARGET_LINUX) |
|
|
||
| <CreatedumpSupportName>libnativeaot-createdump-disabled</CreatedumpSupportName> | ||
| <!-- Linked createdump requires the standard executable bootstrap to handle self-restart. --> | ||
| <CreatedumpSupportName Condition="'$(CreatedumpSupport)' == 'true' and '$(_targetOS)' == 'linux' and '$(IsNativeExecutable)' == 'true' and '$(CustomNativeMain)' != 'true'">libnativeaot-createdump-enabled</CreatedumpSupportName> |
|
cc @dotnet/dotnet-diag-contrib |
|
FYI this is PR is an experiment -- it's nowhere near ready to be merged and haven't looked at all the code. @eduardo-vp this is the PR that I mentioned I was experimenting with I think the work to shrink NAOT dumps is one of the most interesting parts and could even make it into createdump |
This PR is an experiment I've been working on, only sharing as draft so other people can look at it
Summary
Linked support is enabled with
CreatedumpSupport=trueand is intentionally scoped to standard Linux NativeAOT executables. Native libraries and custom native mains remain on the existing external-createdump path.Validation
CreatedumpLinkedInNativeAOT smoke test through the NativeAOT launcherPT_LOAD,NT_FILE,NT_PRSTATUS, andNT_SIGINFOcontents and runtime page-size metadataAn end-to-end seven-run comparison against the original proposal reduced median dump time from 443.90 ms to 427.37 ms and dump size from 38.95 MiB to 31.44 MiB.
Full-tree validation with the current SDK is blocked by pre-existing incompatibilities on this older branch, including NativeAOT task/target skew and runtime-pack manifest churn; targeted builds and tests pass.