Skip to content

Commit ad86979

Browse files
authored
fix: support EOF opcodes in cast da (#9070)
* fix: support EOF opcodes in cast da * fix * fix doc * fmt
1 parent 373ad46 commit ad86979

File tree

5 files changed

+58
-9
lines changed

5 files changed

+58
-9
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cast/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ alloy-sol-types.workspace = true
5454
alloy-transport.workspace = true
5555

5656
chrono.workspace = true
57-
evm-disassembler.workspace = true
5857
eyre.workspace = true
5958
futures.workspace = true
6059
rand.workspace = true

crates/cast/bin/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ async fn main_args(args: CastArgs) -> Result<()> {
307307
println!("Computed Address: {}", computed.to_checksum(None));
308308
}
309309
CastSubcommand::Disassemble { bytecode } => {
310-
println!("{}", SimpleCast::disassemble(&bytecode)?);
310+
println!("{}", SimpleCast::disassemble(&hex::decode(bytecode)?)?);
311311
}
312312
CastSubcommand::Selectors { bytecode, resolve } => {
313313
let functions = SimpleCast::extract_functions(&bytecode)?;

crates/cast/src/lib.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use alloy_sol_types::sol;
2121
use alloy_transport::Transport;
2222
use base::{Base, NumberWithBase, ToBase};
2323
use chrono::DateTime;
24-
use evm_disassembler::{disassemble_bytes, disassemble_str, format_operations};
2524
use eyre::{Context, ContextCompat, Result};
2625
use foundry_block_explorers::Client;
2726
use foundry_common::{
@@ -37,6 +36,7 @@ use rayon::prelude::*;
3736
use revm::primitives::Eof;
3837
use std::{
3938
borrow::Cow,
39+
fmt::Write,
4040
io,
4141
marker::PhantomData,
4242
path::PathBuf,
@@ -45,6 +45,7 @@ use std::{
4545
time::Duration,
4646
};
4747
use tokio::signal::ctrl_c;
48+
use utils::decode_instructions;
4849

4950
use foundry_common::abi::encode_function_args_packed;
5051
pub use foundry_evm::*;
@@ -670,7 +671,7 @@ where
670671
if disassemble {
671672
let code =
672673
self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?.to_vec();
673-
Ok(format_operations(disassemble_bytes(code)?)?)
674+
SimpleCast::disassemble(&code)
674675
} else {
675676
Ok(format!(
676677
"{}",
@@ -1959,17 +1960,36 @@ impl SimpleCast {
19591960
/// # Example
19601961
///
19611962
/// ```
1963+
/// use alloy_primitives::hex;
19621964
/// use cast::SimpleCast as Cast;
19631965
///
19641966
/// # async fn foo() -> eyre::Result<()> {
19651967
/// let bytecode = "0x608060405260043610603f57600035";
1966-
/// let opcodes = Cast::disassemble(bytecode)?;
1968+
/// let opcodes = Cast::disassemble(&hex::decode(bytecode)?)?;
19671969
/// println!("{}", opcodes);
19681970
/// # Ok(())
19691971
/// # }
19701972
/// ```
1971-
pub fn disassemble(bytecode: &str) -> Result<String> {
1972-
format_operations(disassemble_str(bytecode)?)
1973+
pub fn disassemble(code: &[u8]) -> Result<String> {
1974+
let mut output = String::new();
1975+
1976+
for step in decode_instructions(code) {
1977+
write!(output, "{:08x}: ", step.pc)?;
1978+
1979+
if let Some(op) = step.op {
1980+
write!(output, "{op}")?;
1981+
} else {
1982+
write!(output, "INVALID")?;
1983+
}
1984+
1985+
if !step.immediate.is_empty() {
1986+
write!(output, " {}", hex::encode_prefixed(step.immediate))?;
1987+
}
1988+
1989+
writeln!(output)?;
1990+
}
1991+
1992+
Ok(output)
19731993
}
19741994

19751995
/// Gets the selector for a given function signature

crates/evm/core/src/ic.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use alloy_primitives::map::HashMap;
2-
use revm::interpreter::opcode::{PUSH0, PUSH1, PUSH32};
2+
use revm::interpreter::{
3+
opcode::{PUSH0, PUSH1, PUSH32},
4+
OpCode,
5+
};
6+
use revm_inspectors::opcode::immediate_size;
37

48
/// Maps from program counter to instruction counter.
59
///
@@ -84,3 +88,30 @@ fn make_map<const PC_FIRST: bool>(code: &[u8]) -> HashMap<usize, usize> {
8488
}
8589
map
8690
}
91+
92+
/// Represents a single instruction consisting of the opcode and its immediate data.
93+
pub struct Instruction<'a> {
94+
/// OpCode, if it could be decoded.
95+
pub op: Option<OpCode>,
96+
/// Immediate data following the opcode.
97+
pub immediate: &'a [u8],
98+
/// Program counter of the opcode.
99+
pub pc: usize,
100+
}
101+
102+
/// Decodes raw opcode bytes into [`Instruction`]s.
103+
pub fn decode_instructions(code: &[u8]) -> Vec<Instruction<'_>> {
104+
let mut pc = 0;
105+
let mut steps = Vec::new();
106+
107+
while pc < code.len() {
108+
let op = OpCode::new(code[pc]);
109+
let immediate_size = op.map(|op| immediate_size(op, &code[pc + 1..])).unwrap_or(0) as usize;
110+
111+
steps.push(Instruction { op, pc, immediate: &code[pc + 1..pc + 1 + immediate_size] });
112+
113+
pc += 1 + immediate_size;
114+
}
115+
116+
steps
117+
}

0 commit comments

Comments
 (0)