Skip to content

feat(sframe): complete SFrame V2 parser — replace stub with full implementation#471

Open
jbachorik wants to merge 4 commits into
mainfrom
jb/sframe
Open

feat(sframe): complete SFrame V2 parser — replace stub with full implementation#471
jbachorik wants to merge 4 commits into
mainfrom
jb/sframe

Conversation

@jbachorik

@jbachorik jbachorik commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?:

Completes the SFrame V2 parser that was (mistakenly) partially landed in #491 (stub parseFDE returning true, integration removed from parseDwarfInfo). This PR replaces the stub with the full implementation and restores the SFrame-before-DWARF fast path.

parseDwarfInfo() now checks for a .sframe section first via PT_GNU_SFRAME. If present and valid, it parses the SFrame data directly into the existing FrameDesc* table and returns. If absent or invalid, it falls back to the existing .eh_frame DWARF path. Walk-time code (StackWalker::walkDwarf(), CodeCache::findFrameDesc()) is completely unchanged.

Motivation:

SFrame is a simpler ELF section format that directly encodes CFA/FP/RA offsets in flat, binary-searchable tables without requiring a DWARF CFI bytecode interpreter. On modern Linux distros (Fedora 43+, glibc 2.42+, binutils 2.40+), libraries ship .sframe sections alongside .eh_frame. Parsing SFrame is faster than interpreting DWARF opcodes at library load time.

SFrame V2 reference material:

  • SFrame V2 specification — canonical format description: magic, header layout, FDE func_info byte (bit 0 = FDE type, bits 1–2 = FRE addr size), FRE info byte (bit 0 = CFA base, bits 1–2 = offset width, bit 3 = RA tracked, bit 4 = FP tracked), and per-FRE offset stream order (CFA, then RA if tracked, then FP if tracked).
  • binutils include/sframe.h — authoritative C header with all magic constants, struct definitions, and accessor macros.
  • binutils libsframe source — reference reader/writer implementation.
  • SFrame intro blog post (Oracle) — approachable overview of why SFrame exists and how it compares to .eh_frame.

Additional Notes:

  • Linux/ELF only. macOS is unaffected (PT_GNU_SFRAME is never found on Mach-O).
  • No new user-visible CStack mode.
  • Both x86_64 and aarch64 supported, including aarch64 GCC vs Clang default frame detection.
  • SFrameParser is self-contained (sframe.h/sframe.cpp), depends only on dwarf.h.
  • No external dependencies. No build file changes (Gradle auto-discovers new files).
  • Hardening applied during review:
    • OOM detection in addRecord; fde->fre_off pre-check before pointer arithmetic.
    • CFA 24-bit overflow guard; may_alias on packed structs; qsort skipped when SFRAME_F_FDE_SORTED is set.
    • section_offset_full > UINT32_MAX guard before u32 cast in parseDwarfInfo; falls back to DWARF with a warning.
    • Per-FRE offset stream order corrected: RA offset is read before FP offset per the V2 spec (fixes aarch64 frames that track both simultaneously).
    • Partial-FDE rollback: _count and _linked_frame_size are restored when parseFDE fails mid-FDE for non-OOM reasons, preventing corrupt partial entries from surviving in the unwind table.

How to test the change?:

  • 30+ unit tests in sframe_ut.cpp covering: header validation, FDE loop (empty/PCMASK/empty-FRE skip), FRE parsing (SP/FP-based CFA, fixed/per-FRE RA, leaf functions), offset encodings (1B, 2B, 4B), multiple FDEs with sort verification (including reverse-order input), address translation with non-zero section_offset, FRE bounds overrun recovery, destructor memory safety, aarch64 default frame detection, auxhdr_len positive path, reserved encoding rejection, individual bounds guard coverage, both-RA-and-FP-tracked offset assignment, partial-FDE rollback (count and _linked_frame_size).
  • ./gradlew :ddprof-lib:gtestDebug — all SFrame tests pass (Linux); existing DWARF tests unaffected.
  • ./gradlew :ddprof-lib:buildRelease — builds cleanly on both Linux and macOS.
  • Integration on modern Linux (Fedora 43+): profile a Java app with cstack=dwarf, verify native stacks are collected via the SFrame fast path.

For Datadog employees:

  • If this PR touches code that signs or publishes builds or packages, or handles
    credentials of any kind, I've requested a review from @DataDog/security-design-and-guidance.
  • This PR doesn't touch any of that.
  • JIRA: [JIRA-XXXX]

Unsure? Have a question? Request a review!

@jbachorik jbachorik added the AI label Apr 14, 2026
@dd-octo-sts

dd-octo-sts Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

CI Test Results

Run: #27331660222 | Commit: e82f6fd | Duration: 12m 35s (longest job)

All 32 test jobs passed

Status Overview

JDK glibc-aarch64/debug glibc-amd64/debug musl-aarch64/debug musl-amd64/debug
8 - - -
8-ibm - - -
8-j9 - -
8-librca - -
8-orcl - - -
11 - - -
11-j9 - -
11-librca - -
17 - -
17-graal - -
17-j9 - -
17-librca - -
21 - -
21-graal - -
21-librca - -
25 - -
25-graal - -
25-librca - -

Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled

Summary: Total: 32 | Passed: 32 | Failed: 0


Updated: 2026-06-11 07:58:02 UTC

@jbachorik jbachorik changed the title Parse .sframe sections as alternative to .eh_frame feat(sframe): complete SFrame V2 parser — replace stub with full implementation Jun 10, 2026
@datadog-official

This comment has been minimized.

@jbachorik

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64163413cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ddprof-lib/src/main/cpp/sframe.cpp
Comment thread ddprof-lib/src/main/cpp/sframe.cpp Outdated

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

This PR completes the Linux/ELF SFrame V2 parsing path and wires it back into library load-time unwind table construction, preferring .sframe (via PT_GNU_SFRAME) before falling back to the existing .eh_frame DWARF parser.

Changes:

  • Implement full SFrame V2 FDE/FRE parsing in SFrameParser and add additional validation/hardening.
  • Restore the “SFrame-first” fast path in ElfParser::parseDwarfInfo() on Linux.
  • Add extensive unit test coverage for SFrame parsing edge cases and validation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
ddprof-lib/src/test/cpp/sframe_ut.cpp Adds broad SFrame parser unit tests (header/FDE/FRE validation, bounds checks, sorting, arch behaviors).
ddprof-lib/src/main/cpp/symbols_linux.cpp Tries PT_GNU_SFRAME first and uses SFrameParser to populate CodeCache unwind tables before DWARF fallback.
ddprof-lib/src/main/cpp/sframe.h Adds may_alias packed structs and OOM tracking state to SFrameParser.
ddprof-lib/src/main/cpp/sframe.cpp Replaces the parseFDE stub with a full implementation and expands validation/sorting logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ddprof-lib/src/main/cpp/sframe.cpp
Comment thread ddprof-lib/src/main/cpp/sframe.cpp
Comment thread ddprof-lib/src/main/cpp/symbols_linux.cpp

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread ddprof-lib/src/main/cpp/sframe.cpp
Comment thread ddprof-lib/src/main/cpp/sframe.cpp
@jbachorik jbachorik marked this pull request as ready for review June 10, 2026 15:17
@jbachorik jbachorik requested a review from a team as a code owner June 10, 2026 15:17

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07dfb1908c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ddprof-lib/src/main/cpp/sframe.cpp
jbachorik and others added 4 commits June 11, 2026 08:23
Replaces the stub parseFDE with the full implementation and
restores the SFrame-before-DWARF integration in parseDwarfInfo.

Includes fixes from sphinx review: OOM handling, fre_off bounds
check, cfa_fixed_fp_offset, unsigned loc arithmetic, CFA overflow
guard, may_alias annotation, qsort flag guard, and expanded tests.
…uard

- parseFDE: read RA offset before FP offset per SFrame V2 spec (CFA, RA, FP)
- parse: save/restore _count and _linked_frame_size on non-OOM parseFDE failure
- parseDwarfInfo: guard section_offset_full > UINT32_MAX before u32 cast
- sframe_ut: fix buildFRE_{1B,2B,4B} wire order (RA before FP); add tests
  for both-tracked offset assignment, partial-FDE rollback (count and
  _linked_frame_size), and section-offset overflow guard documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants