Schema
- Explore
- View source
- Playground
Loading ....
- YAML
- JSON
ethdebug/format/pointer
$schema: "https://json-schema.org/draft/2020-12/schema"
$id: "schema:ethdebug/format/pointer"
title: ethdebug/format/pointer
description: |
A schema for representing a pointer to a data position or a range of data
positions in the EVM.
An **ethdebug/format/pointer** is either a single region or a structured
collection of other pointers.
type: object
if:
required: [location]
then:
$ref: "schema:ethdebug/format/pointer/region"
else:
$ref: "schema:ethdebug/format/pointer/collection"
examples:
- # example: a single particular storage slot
location: storage
slot: 2
- # example `uint256[] memory` allocation pointer
define:
"uint256-array-memory-pointer-slot": 0
in:
# this pointer composes an ordered list of other pointers
group:
# declare the first sub-pointer to be the "array-start" region of data
# corresponding to the first item in the stack (at time of observation)
- name: "array-start"
location: stack
slot: "uint256-array-memory-pointer-slot"
# declare the "array-count" region to be at the offset indicated by
# the value at "array-start"
- name: "array-count"
location: memory
offset:
$read: "array-start"
length: $wordsize
# thirdly, declare a sub-pointer that is a dynamic list whose size is
# indicated by the value at "array-count", where each "item-index"
# corresponds to a discrete "array-item" region
- list:
count:
$read: "array-count"
each: "item-index"
is:
name: "array-item"
location: "memory"
offset:
# array items are positioned so that the item with index 0
# immediately follows "array-count", and each subsequent item
# immediately follows the previous.
$sum:
- .offset: "array-count"
- .length: "array-count"
- $product:
- "item-index"
- .length: $this
length: $wordsize
- # example `struct Record { uint8 x; uint8 y; bytes4 salt; }` in storage
define:
"struct-storage-contract-variable-slot": 0
in:
group:
- name: "x"
location: storage
slot: "struct-storage-contract-variable-slot"
offset:
$difference:
- $wordsize
- .length: $this
length: 1 # uint8
- name: "y"
location: storage
slot: "struct-storage-contract-variable-slot"
offset:
$difference:
- .offset: "x"
- .length: $this
length: 1 # uint8
- name: "salt"
location: storage
slot: "struct-storage-contract-variable-slot"
offset:
$difference:
- .offset: "y"
- .length: $this
length: 4 # bytes4
- # example `(struct Record { uint256 x; uint256 y; })[] memory`
group:
# declare the first sub-pointer to be the "array-start" region of data
# corresponding to the first item in the stack (at time of observation)
- name: "array-start"
location: stack
slot: 0
# declares the "array-count" region in memory at the offset indicated
# by "array-start" and of length equal to word size
- name: "array-count"
location: memory
offset:
$read: "array-start"
length: $wordsize
# declare this to include a list of pointers of size indicated by the
# value at "array-count", where each "item-index" corresponds to a
# group of pointers
- list:
count:
$read: "array-count"
each: "item-index"
is:
group:
# each element in the list includes a "struct-pointer" region
# in memory (laid out sequentially in a block as the raw
# array data)
- name: "struct-pointer"
location: memory
offset:
$sum:
- .offset: "array-count"
- .length: "array-count"
- $product:
- "item-index"
- .length: "struct-pointer"
length: $wordsize
# following that pointer leads to the region corresponding to
# the first member of the struct
- name: "struct-member-0"
location: memory
offset:
$read: "struct-pointer"
length: $wordsize
# the second struct member immediately follows the first
- name: "struct-member-1"
location: memory
offset:
$sum:
- .offset: "struct-member-0"
- .length: "struct-member-0"
length: $wordsize
- # example `string storage` allocation
define:
"string-storage-contract-variable-slot": 0
in:
group:
# for short strings, the length is stored as 2n in the last byte of slot
- name: "length-flag"
location: storage
slot: "string-storage-contract-variable-slot"
offset:
$difference: [$wordsize, 1]
length: 1
# define the region representing the string data itself conditionally
# based on odd or even length data
- if:
$remainder:
- $sum:
- $read: "length-flag"
- 1
- 2
# short string case (flag is even)
then:
define:
"string-length":
$quotient: [{ $read: "length-flag" }, 2]
in:
name: "string"
location: storage
slot: "string-storage-contract-variable-slot"
offset: 0
length: "string-length"
# long string case (flag is odd)
else:
group:
# long strings may use full word to describe length as 2n+1
- name: "long-string-length-data"
location: storage
slot: "string-storage-contract-variable-slot"
offset: 0
length: $wordsize
- define:
"string-length":
$quotient:
- $difference:
- $read: "long-string-length-data"
- 1
- 2
"start-slot":
$keccak256:
- $wordsized: "string-storage-contract-variable-slot"
"total-slots":
# account for both zero and nonzero slot remainders by adding
# $wordsize-1 to the length before dividing
$quotient:
- $sum: ["string-length", { $difference: [$wordsize, 1] }]
- $wordsize
in:
list:
count: "total-slots"
each: "i"
is:
define:
"current-slot":
$sum: ["start-slot", "i"]
"previous-length":
$product: ["i", $wordsize]
in:
# conditional based on whether this is the last slot:
# is the string length longer than the previous length
# plus this whole slot?
if:
$difference:
- "string-length"
- $sum: ["previous-length", "$wordsize"]
then:
# include the whole slot
name: "string"
location: storage
slot: "current-slot"
else:
# include only what's left in the string
name: "string"
location: storage
slot: "current-slot"
offset: 0
length:
$difference: ["string-length", "previous-length"]
ethdebug/format/pointer
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ethdebug/format/pointer",
"title": "ethdebug/format/pointer",
"description": "A schema for representing a pointer to a data position or a range of data\npositions in the EVM.\n\nAn **ethdebug/format/pointer** is either a single region or a structured\ncollection of other pointers.\n",
"type": "object",
"if": {
"required": [
"location"
]
},
"then": {
"$ref": "schema:ethdebug/format/pointer/region"
},
"else": {
"$ref": "schema:ethdebug/format/pointer/collection"
},
"examples": [
{
"location": "storage",
"slot": 2
},
{
"define": {
"uint256-array-memory-pointer-slot": 0
},
"in": {
"group": [
{
"name": "array-start",
"location": "stack",
"slot": "uint256-array-memory-pointer-slot"
},
{
"name": "array-count",
"location": "memory",
"offset": {
"$read": "array-start"
},
"length": "$wordsize"
},
{
"list": {
"count": {
"$read": "array-count"
},
"each": "item-index",
"is": {
"name": "array-item",
"location": "memory",
"offset": {
"$sum": [
{
".offset": "array-count"
},
{
".length": "array-count"
},
{
"$product": [
"item-index",
{
".length": "$this"
}
]
}
]
},
"length": "$wordsize"
}
}
}
]
}
},
{
"define": {
"struct-storage-contract-variable-slot": 0
},
"in": {
"group": [
{
"name": "x",
"location": "storage",
"slot": "struct-storage-contract-variable-slot",
"offset": {
"$difference": [
"$wordsize",
{
".length": "$this"
}
]
},
"length": 1
},
{
"name": "y",
"location": "storage",
"slot": "struct-storage-contract-variable-slot",
"offset": {
"$difference": [
{
".offset": "x"
},
{
".length": "$this"
}
]
},
"length": 1
},
{
"name": "salt",
"location": "storage",
"slot": "struct-storage-contract-variable-slot",
"offset": {
"$difference": [
{
".offset": "y"
},
{
".length": "$this"
}
]
},
"length": 4
}
]
}
},
{
"group": [
{
"name": "array-start",
"location": "stack",
"slot": 0
},
{
"name": "array-count",
"location": "memory",
"offset": {
"$read": "array-start"
},
"length": "$wordsize"
},
{
"list": {
"count": {
"$read": "array-count"
},
"each": "item-index",
"is": {
"group": [
{
"name": "struct-pointer",
"location": "memory",
"offset": {
"$sum": [
{
".offset": "array-count"
},
{
".length": "array-count"
},
{
"$product": [
"item-index",
{
".length": "struct-pointer"
}
]
}
]
},
"length": "$wordsize"
},
{
"name": "struct-member-0",
"location": "memory",
"offset": {
"$read": "struct-pointer"
},
"length": "$wordsize"
},
{
"name": "struct-member-1",
"location": "memory",
"offset": {
"$sum": [
{
".offset": "struct-member-0"
},
{
".length": "struct-member-0"
}
]
},
"length": "$wordsize"
}
]
}
}
}
]
},
{
"define": {
"string-storage-contract-variable-slot": 0
},
"in": {
"group": [
{
"name": "length-flag",
"location": "storage",
"slot": "string-storage-contract-variable-slot",
"offset": {
"$difference": [
"$wordsize",
1
]
},
"length": 1
},
{
"if": {
"$remainder": [
{
"$sum": [
{
"$read": "length-flag"
},
1
]
},
2
]
},
"then": {
"define": {
"string-length": {
"$quotient": [
{
"$read": "length-flag"
},
2
]
}
},
"in": {
"name": "string",
"location": "storage",
"slot": "string-storage-contract-variable-slot",
"offset": 0,
"length": "string-length"
}
},
"else": {
"group": [
{
"name": "long-string-length-data",
"location": "storage",
"slot": "string-storage-contract-variable-slot",
"offset": 0,
"length": "$wordsize"
},
{
"define": {
"string-length": {
"$quotient": [
{
"$difference": [
{
"$read": "long-string-length-data"
},
1
]
},
2
]
},
"start-slot": {
"$keccak256": [
{
"$wordsized": "string-storage-contract-variable-slot"
}
]
},
"total-slots": {
"$quotient": [
{
"$sum": [
"string-length",
{
"$difference": [
"$wordsize",
1
]
}
]
},
"$wordsize"
]
}
},
"in": {
"list": {
"count": "total-slots",
"each": "i",
"is": {
"define": {
"current-slot": {
"$sum": [
"start-slot",
"i"
]
},
"previous-length": {
"$product": [
"i",
"$wordsize"
]
}
},
"in": {
"if": {
"$difference": [
"string-length",
{
"$sum": [
"previous-length",
"$wordsize"
]
}
]
},
"then": {
"name": "string",
"location": "storage",
"slot": "current-slot"
},
"else": {
"name": "string",
"location": "storage",
"slot": "current-slot",
"offset": 0,
"length": {
"$difference": [
"string-length",
"previous-length"
]
}
}
}
}
}
}
}
]
}
}
]
}
}
]
}
Loading...