Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support EOF opcodes in cast da #9070

Merged
merged 4 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading