[DynInst_API:] [dyninst/dyninst] 657368: symtab/dyninstAPI: synthesize eh_frame + gcc_excep...


Date: Mon, 06 Jul 2026 00:05:13 -0700
From: bbiiggppiigg <noreply@xxxxxxxxxx>
Subject: [DynInst_API:] [dyninst/dyninst] 657368: symtab/dyninstAPI: synthesize eh_frame + gcc_excep...
  Branch: refs/heads/bbiiggppiigg/eh-frame-lsda
  Home:   https://github.com/dyninst/dyninst
  Commit: 65736833134c78d40b62109bb82b190463c3c1cd
      https://github.com/dyninst/dyninst/commit/65736833134c78d40b62109bb82b190463c3c1cd
  Author: wuxx1279 <bbiiggppiigg@xxxxxxxxx>
  Date:   2026-07-06 (Mon, 06 Jul 2026)

  Changed paths:
    M common/src/debug_common.C
    M common/src/debug_common.h
    M dyninstAPI/src/binaryEdit.C
    M dyninstAPI_RT/src/RTcommon.c
    M symtabAPI/h/Symtab.h
    M symtabAPI/src/Object-elf.C
    M symtabAPI/src/Object-elf.h
    M symtabAPI/src/Symtab.C

  Log Message:
  -----------
  symtab/dyninstAPI: synthesize eh_frame + gcc_except_table for relocated code (#1437)

Dyninst relocates instrumented functions into a new segment (.dyninstInst) but
emits no unwind info for the relocated code. When a relocated function is on the
stack during a C++ throw, libgcc's unwinder finds no FDE for the relocated PC and
calls std::terminate() -- so any exception thrown through, or caught in, an
instrumented frame aborts the program (issue #1437).

Generate unwind + exception-handling info for the relocated code at rewrite time
and register it at process startup:

  * symtabAPI: Symtab::getCFALocations() exposes the original .eh_frame CFA rules
    per PC range (via DwarfFrameParser); Symtab::getEHFrameInfo() decodes each
    function's LSDA (call-site table, action table, type table, personality) from
    .eh_frame + .gcc_except_table.

  * dyninstAPI (binaryEdit): for every relocated function emit one FDE spanning
    its relocated extent, with CFA rules mapped from the original .eh_frame. A
    function that carried an LSDA also gets a "zPLR" CIE and a regenerated
    .gcc_except_table whose call sites + landing pads are remapped block-by-block
    through the CodeTracker (a function's hot and cold partitions merge into one
    table). Pointers are pcrel where we own both ends; personality and type-table
    entries preserve the original encoding (pcrel for PIE, absolute/udata4 for
    non-PIE). The blobs live in loadable .dyninst_ehframe / .dyninst_gcc_except
    regions with an exported __dyninst_eh_frame symbol. This runs for DYNAMICally
    linked output only (guarded by !isStaticBinary()).

  * dyninstAPI_RT: DYNINSTBaseInit() reads the weak __dyninst_eh_frame and libgcc's
    weak __register_frame and registers the synthesized FDEs at startup. This is
    compiled out of the static RT (#ifndef DYNINST_RT_STATIC_LIB): the static
    rewriter mis-relocates any new global-data reference added to the relocated
    DYNINSTBaseInit (it links the RT at emit, after such references are computed),
    which crashed statically-linked rewritten binaries. Static-binary exception
    support needs a rewriter-aware delivery (post-link patching / runtime scan)
    and is left as follow-up; dynamic binaries are unaffected.

  * common: add eh_printf (gated by DYNINST_DEBUG_EH) for diagnostics.

Verified with the #1437 reproducer (a function instrumented while on the stack
during a throw) for PIE and non-PIE dynamically-linked binaries, and on
641.leela_s. The static rewriter test suite passes with no crashes (registration
compiled out of the static RT).

Co-Authored-By: Claude Fable 5 <noreply@xxxxxxxxxxxxx>



To unsubscribe from these emails, change your notification settings at https://github.com/dyninst/dyninst/settings/notifications
[← Prev in Thread] Current Thread [Next in Thread→]
  • [DynInst_API:] [dyninst/dyninst] 657368: symtab/dyninstAPI: synthesize eh_frame + gcc_excep..., bbiiggppiigg <=