Skip to content

format: define the four edges of an internal function call #348

Description

@gnidan

Now that instruction contexts are postconditions (#281, and #302 for external calls), the function contexts need another pass for internal calls. ethdebug/format/program/context/function/invoke says to put the context on the callee's entry JUMPDEST because "the caller's JUMP has consumed its destination operand by then", but that's just as true after the caller's JUMP. ethdebug/format/program/context/function/return only says the instruction "is associated with a successful function return", which doesn't tell anyone whether the function is still active after that instruction, or where the context belongs.

This shows up in our own tools. bugc puts return on the caller's continuation JUMPDEST, and the trace viewer pops the frame one step after that, so a frame stays on the call stack for two steps after control is back in the caller. Going in, the timing is exact. Neither tool is wrong according to the spec as written, which is the problem.

I've thought for a long time that an internal call has four edges, not two (this is where #141's "call setup / body / cleanup" and my comment on #41 were heading): the call (the caller's JUMP), the entry (the callee's JUMPDEST), the exit (the callee's JUMP back), and the resume (the caller's JUMPDEST after the call). JUMPDEST changes no state, so the edges pair up by what's true after them, but each knows something different: call and resume know the call site (and might not know the callee, if the jump is computed; see #290), while entry and exit know the function but not the caller. That's the same split DWARF makes between DW_TAG_call_site and DW_TAG_subprogram. Under the postcondition rule, the frame should change at the two edges that transfer control: after the call, the callee is active, and after the exit, it isn't. Today nothing marks the exit.

I'd like to do this in two passes. First, clarify what exists: say what invoke and return mean under postconditions, fix the invoke rationale, and recommend placement, so current producers and debuggers agree on timing. Second, add what's missing: decide how the four edges are represented (distinct kinds, or invoke/return plus call-site data), how activation (#245) pairs them, and how reverts fit, then update bugc and the trace viewer together.

Both passes change what debuggers have to handle, so solc, Fe and Solar will get a heads-up before anything ships. Modifiers (#313) raise the same questions about edges and may end up sharing this design.


Drafted by Claude. gnidan approved writing as "I" on his behalf for this issue.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions