Skip to content

Commit da7f541

Browse files
committed
Add function call tracing documentation
Add invoke/return/revert context documentation across concept, reference, and spec pages: - concepts/programs.mdx: new "Function call contexts" section explaining the three context types with a SchemaExample - tracing.mdx: walkthrough of tracing through an internal function call (Adder contract), plus external call and revert examples - Spec pages: added intro prose to function.mdx, return.mdx, revert.mdx
1 parent da00fb8 commit da7f541

5 files changed

Lines changed: 230 additions & 1 deletion

File tree

packages/web/docs/concepts/programs.mdx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,55 @@ Contexts can be composed using:
157157
This composition enables describing complex scenarios like conditional variable
158158
assignments or function inlining.
159159

160+
## Function call contexts
161+
162+
Programs answer "what function are we in?" through three context types
163+
that track function boundaries during execution:
164+
165+
- **invoke** — marks an instruction that enters a function. Indicates
166+
the invocation kind (internal jump, external message call, or
167+
contract creation) and provides pointers to call arguments, target
168+
address, gas, and value as appropriate.
169+
- **return** — marks an instruction associated with a successful
170+
return from a function. Provides a pointer to the return data.
171+
- **revert** — marks an instruction associated with a failed call.
172+
May include a pointer to revert reason data or a numeric panic
173+
code.
174+
175+
All three extend a common **function identity** schema with optional
176+
fields for the function's name, declaration source range, and type.
177+
This lets compilers provide as much or as little attribution as
178+
available — from a fully identified `transfer` call down to an
179+
anonymous indirect invocation through a function pointer.
180+
181+
<SchemaExample
182+
schema="program/context/function/invoke"
183+
href="/spec/program/context/function/invoke"
184+
title="Internal function call"
185+
>
186+
{`{
187+
"invoke": {
188+
"identifier": "transfer",
189+
"jump": true,
190+
"target": {
191+
"pointer": { "location": "stack", "slot": 0 }
192+
},
193+
"arguments": {
194+
"pointer": {
195+
"group": [
196+
{ "name": "to", "location": "stack", "slot": 2 },
197+
{ "name": "amount", "location": "stack", "slot": 3 }
198+
]
199+
}
200+
}
201+
}
202+
}`}
203+
</SchemaExample>
204+
205+
A debugger uses these contexts to reconstruct call stacks, show
206+
function names in stepping UI, and display argument/return values
207+
alongside source code.
208+
160209
## What tracing enables
161210

162211
By following contexts through execution, debuggers can provide:

packages/web/docs/core-schemas/programs/tracing.mdx

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,172 @@ b = b + 1;
121121
}`}
122122
/>
123123

124+
## Tracing through a function call
125+
126+
The examples above trace simple straight-line code. Real programs
127+
make function calls. **invoke** and **return** contexts let a
128+
debugger follow execution across function boundaries.
129+
130+
Consider a contract with an internal `add` function:
131+
132+
```
133+
name Adder;
134+
135+
storage {
136+
[0] result: uint256;
137+
}
138+
139+
create {
140+
result = 0;
141+
}
142+
143+
func add(a: uint256, b: uint256) -> uint256 {
144+
return a + b;
145+
}
146+
147+
code {
148+
result = add(3, 4);
149+
}
150+
```
151+
152+
The compiler produces a sequence of instructions. The relevant
153+
instructions look like this (offsets are illustrative):
154+
155+
### Before the call — setting up arguments
156+
157+
At the call site, the compiler pushes arguments onto the stack and
158+
prepares the jump. The instruction at the JUMP has an **invoke**
159+
context:
160+
161+
<SchemaExample
162+
schema="program/context/function/invoke"
163+
href="/spec/program/context/function/invoke"
164+
title="Instruction at call site (JUMP)"
165+
>
166+
{`{
167+
"invoke": {
168+
"identifier": "add",
169+
"jump": true,
170+
"target": {
171+
"pointer": { "location": "stack", "slot": 0 }
172+
},
173+
"arguments": {
174+
"pointer": {
175+
"group": [
176+
{ "name": "a", "location": "stack", "slot": 2 },
177+
{ "name": "b", "location": "stack", "slot": 3 }
178+
]
179+
}
180+
}
181+
}
182+
}`}
183+
</SchemaExample>
184+
185+
The debugger now knows it's entering `add` with arguments at stack
186+
slots 2 and 3. A trace viewer can show `add(3, 4)` in the call
187+
stack.
188+
189+
### Inside the function — normal tracing
190+
191+
Inside `add`, instructions carry their own `code` and `variables`
192+
contexts as usual. The debugger shows the source range within the
193+
function body, and parameters `a` and `b` appear as in-scope
194+
variables.
195+
196+
### Returning — the result
197+
198+
When `add` finishes, the JUMP back to the caller has a **return**
199+
context:
200+
201+
<SchemaExample
202+
schema="program/context/function/return"
203+
href="/spec/program/context/function/return"
204+
title="Instruction at return site (JUMP)"
205+
>
206+
{`{
207+
"return": {
208+
"identifier": "add",
209+
"data": {
210+
"pointer": { "location": "stack", "slot": 0 }
211+
}
212+
}
213+
}`}
214+
</SchemaExample>
215+
216+
The debugger pops `add` from the call stack and can display the
217+
return value (7).
218+
219+
### External calls and reverts
220+
221+
The same pattern applies to external message calls, but with
222+
additional fields. An external CALL instruction carries gas, value,
223+
and input data pointers:
224+
225+
<SchemaExample
226+
schema="program/context/function/invoke"
227+
href="/spec/program/context/function/invoke"
228+
title="External call (CALL)"
229+
>
230+
{`{
231+
"invoke": {
232+
"identifier": "balanceOf",
233+
"message": true,
234+
"target": {
235+
"pointer": { "location": "stack", "slot": 1 }
236+
},
237+
"gas": {
238+
"pointer": { "location": "stack", "slot": 0 }
239+
},
240+
"input": {
241+
"pointer": {
242+
"group": [
243+
{ "name": "selector", "location": "memory",
244+
"offset": "0x80", "length": 4 },
245+
{ "name": "arguments", "location": "memory",
246+
"offset": "0x84", "length": "0x20" }
247+
]
248+
}
249+
}
250+
}
251+
}`}
252+
</SchemaExample>
253+
254+
If the call reverts, a **revert** context captures the reason:
255+
256+
<SchemaExample
257+
schema="program/context/function/revert"
258+
href="/spec/program/context/function/revert"
259+
title="Revert with reason"
260+
>
261+
{`{
262+
"revert": {
263+
"identifier": "transfer",
264+
"reason": {
265+
"pointer": {
266+
"location": "memory",
267+
"offset": "0x80",
268+
"length": "0x64"
269+
}
270+
}
271+
}
272+
}`}
273+
</SchemaExample>
274+
275+
For built-in assertion failures, the compiler can provide a panic
276+
code instead of (or alongside) a reason pointer:
277+
278+
<SchemaExample
279+
schema="program/context/function/revert"
280+
href="/spec/program/context/function/revert"
281+
title="Arithmetic overflow panic"
282+
>
283+
{`{
284+
"revert": {
285+
"panic": 17
286+
}
287+
}`}
288+
</SchemaExample>
289+
124290
## Trace data structure
125291

126292
A trace step captures the EVM state at a single point:

packages/web/spec/program/context/function/function.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import SchemaViewer from "@site/src/components/SchemaViewer";
77
# Function identity
88

99
Function contexts (invoke, return, revert) share a common set of
10-
identity fields for the function being called.
10+
identity fields for the function being called. All fields are
11+
optional, allowing compilers to provide as much or as little
12+
detail as available — from a fully named function with source
13+
location and type, down to an empty object for an anonymous
14+
indirect call.
1115

1216
<SchemaViewer
1317
schema={{ id: "schema:ethdebug/format/program/context/function" }}

packages/web/spec/program/context/function/return.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import SchemaViewer from "@site/src/components/SchemaViewer";
66

77
# Return contexts
88

9+
A return context marks an instruction associated with a successful
10+
function return. It extends the function identity schema with a
11+
pointer to the return data and, for external calls, the success
12+
status.
13+
914
<SchemaViewer
1015
schema={{ id: "schema:ethdebug/format/program/context/function/return" }}
1116
/>

packages/web/spec/program/context/function/revert.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import SchemaViewer from "@site/src/components/SchemaViewer";
66

77
# Revert contexts
88

9+
A revert context marks an instruction associated with a function
10+
revert. It extends the function identity schema with an optional
11+
pointer to revert reason data and/or a numeric panic code for
12+
built-in assertion failures.
13+
914
<SchemaViewer
1015
schema={{ id: "schema:ethdebug/format/program/context/function/revert" }}
1116
/>

0 commit comments

Comments
 (0)