Skip to content

Add linked createdump support for NativeAOT executables - #132572

Draft
agocke wants to merge 4 commits into
dotnet:mainfrom
agocke:aot-createdump
Draft

Add linked createdump support for NativeAOT executables#132572
agocke wants to merge 4 commits into
dotnet:mainfrom
agocke:aot-createdump

Conversation

@agocke

@agocke agocke commented Aug 20, 2026

Copy link
Copy Markdown
Member

This PR is an experiment I've been working on, only sharing as draft so other people can look at it

Summary

  • link a compact createdump implementation into explicitly opted-in Linux NativeAOT executables
  • re-execute the current executable to produce ELF core dumps without shipping a separate createdump executable
  • retain the external-createdump path for native libraries, custom native mains, explicit helper overrides, and unsupported dump options
  • harden dump dispatch and ELF generation, including secure-execution checks, crash-thread capture, dynamic page sizes, mapping reconstruction, overflow checks, and partial-file cleanup
  • add executable-level validation of ELF program headers, notes, deleted mappings, dump-name formatting, and external fallback behavior

Linked support is enabled with CreatedumpSupport=true and is intentionally scoped to standard Linux NativeAOT executables. Native libraries and custom native mains remain on the existing external-createdump path.

Validation

  • built the NativeAOT runtime and libraries
  • compiled, linked, and ran the CreatedumpLinkedIn NativeAOT smoke test through the NativeAOT launcher
  • verified linked dump generation plus unsupported-option and explicit-helper fallback
  • verified PT_LOAD, NT_FILE, NT_PRSTATUS, and NT_SIGINFO contents and runtime page-size metadata
  • loaded a generated core in LLDB, selected the crashing thread, enumerated all threads, and unwound stacks
  • verified enabled/disabled archive selection for standard executables, explicit opt-out, custom mains, and shared libraries

An 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.

agocke and others added 4 commits February 22, 2026 15:32
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
Copilot AI lite review requested due to automatic review settings August 20, 2026 16:43
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-enabled static library (Linux, supported arch) containing a minimal /proc + ptrace reader and ELF core writer, plus a disabled stub variant.
  • Update NativeAOT bootstrap + PalCreateDump to 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

  • CalculateNotesSize accumulates note sizes with unchecked arithmetic (including auxv.count * sizeof(Elf64_auxv_t) and repeated total += ...). If this overflows, notesSize can become too small and the file layout computations in WriteElfCoreDump can 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 CalculateNotesSize also needs overflow checks. Without them, a process with many threads could overflow total and cause notesSize to 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

Comment on lines 13 to 14
#include <unistd.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
Comment on lines +156 to +176
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>
@jkotas

jkotas commented Aug 20, 2026

Copy link
Copy Markdown
Member

cc @dotnet/dotnet-diag-contrib

@agocke

agocke commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants