Skip to content

Commit

Permalink
fix: support EOF opcodes in cast da (#9070)
Browse files Browse the repository at this point in the history
* fix: support EOF opcodes in cast da

* fix

* fix doc

* fmt
  • Loading branch information
klkvr authored Oct 9, 2024
1 parent 373ad46 commit ad86979
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 9 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/cast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ alloy-sol-types.workspace = true
alloy-transport.workspace = true

chrono.workspace = true
evm-disassembler.workspace = true
eyre.workspace = true
futures.workspace = true
rand.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/cast/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ async fn main_args(args: CastArgs) -> Result<()> {
println!("Computed Address: {}", computed.to_checksum(None));
}
CastSubcommand::Disassemble { bytecode } => {
println!("{}", SimpleCast::disassemble(&bytecode)?);
println!("{}", SimpleCast::disassemble(&hex::decode(bytecode)?)?);
}
CastSubcommand::Selectors { bytecode, resolve } => {
let functions = SimpleCast::extract_functions(&bytecode)?;
Expand Down
30 changes: 25 additions & 5 deletions crates/cast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use alloy_sol_types::sol;
use alloy_transport::Transport;
use base::{Base, NumberWithBase, ToBase};
use chrono::DateTime;
use evm_disassembler::{disassemble_bytes, disassemble_str, format_operations};
use eyre::{Context, ContextCompat, Result};
use foundry_block_explorers::Client;
use foundry_common::{
Expand All @@ -37,6 +36,7 @@ use rayon::prelude::*;
use revm::primitives::Eof;
use std::{
borrow::Cow,
fmt::Write,
io,
marker::PhantomData,
path::PathBuf,
Expand All @@ -45,6 +45,7 @@ use std::{
time::Duration,
};
use tokio::signal::ctrl_c;
use utils::decode_instructions;

use foundry_common::abi::encode_function_args_packed;
pub use foundry_evm::*;
Expand Down Expand Up @@ -670,7 +671,7 @@ where
if disassemble {
let code =
self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?.to_vec();
Ok(format_operations(disassemble_bytes(code)?)?)
SimpleCast::disassemble(&code)
} else {
Ok(format!(
"{}",
Expand Down Expand Up @@ -1959,17 +1960,36 @@ impl SimpleCast {
/// # Example
///
/// ```
/// use alloy_primitives::hex;
/// use cast::SimpleCast as Cast;
///
/// # async fn foo() -> eyre::Result<()> {
/// let bytecode = "0x608060405260043610603f57600035";
/// let opcodes = Cast::disassemble(bytecode)?;
/// let opcodes = Cast::disassemble(&hex::decode(bytecode)?)?;
/// println!("{}", opcodes);
/// # Ok(())
/// # }
/// ```
pub fn disassemble(bytecode: &str) -> Result<String> {
format_operations(disassemble_str(bytecode)?)
pub fn disassemble(code: &[u8]) -> Result<String> {
let mut output = String::new();

for step in decode_instructions(code) {
write!(output, "{:08x}: ", step.pc)?;

if let Some(op) = step.op {
write!(output, "{op}")?;
} else {
write!(output, "INVALID")?;
}

if !step.immediate.is_empty() {
write!(output, " {}", hex::encode_prefixed(step.immediate))?;
}

writeln!(output)?;
}

Ok(output)
}

/// Gets the selector for a given function signature
Expand Down
33 changes: 32 additions & 1 deletion crates/evm/core/src/ic.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use alloy_primitives::map::HashMap;
use revm::interpreter::opcode::{PUSH0, PUSH1, PUSH32};
use revm::interpreter::{
opcode::{PUSH0, PUSH1, PUSH32},
OpCode,
};
use revm_inspectors::opcode::immediate_size;

/// Maps from program counter to instruction counter.
///
Expand Down Expand Up @@ -84,3 +88,30 @@ fn make_map<const PC_FIRST: bool>(code: &[u8]) -> HashMap<usize, usize> {
}
map
}

/// Represents a single instruction consisting of the opcode and its immediate data.
pub struct Instruction<'a> {
/// OpCode, if it could be decoded.
pub op: Option<OpCode>,
/// Immediate data following the opcode.
pub immediate: &'a [u8],
/// Program counter of the opcode.
pub pc: usize,
}

/// Decodes raw opcode bytes into [`Instruction`]s.
pub fn decode_instructions(code: &[u8]) -> Vec<Instruction<'_>> {
let mut pc = 0;
let mut steps = Vec::new();

while pc < code.len() {
let op = OpCode::new(code[pc]);
let immediate_size = op.map(|op| immediate_size(op, &code[pc + 1..])).unwrap_or(0) as usize;

steps.push(Instruction { op, pc, immediate: &code[pc + 1..pc + 1 + immediate_size] });

pc += 1 + immediate_size;
}

steps
}

0 comments on commit ad86979

Please sign in to comment.