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

feat(debugger): Highlight memory region for any instruction #5940

Merged
merged 2 commits into from
Oct 4, 2023
Merged
Changes from 1 commit
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
84 changes: 66 additions & 18 deletions crates/debugger/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![warn(unused_crate_dependencies)]

use alloy_primitives::Address;
use alloy_primitives::{Address, U256};
use crossterm::{
event::{
self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers,
Expand Down Expand Up @@ -858,6 +858,50 @@ Line::from(Span::styled("[t]: stack labels | [m]: memory decoding | [shift + j/k
f.render_widget(paragraph, area);
}

fn get_memory_access(
soyccan marked this conversation as resolved.
Show resolved Hide resolved
op: u8,
stack: &Vec<U256>,
) -> (Option<usize>, Option<usize>, Option<usize>, Option<usize>) {
// The index on the stack that indicates the memory offset/size to be accessed
// (read memory offset, read memory size, write memory offset, write memory size)
// >= 1: the stack index
// 0: no memory access
// -1: a fixed size of 32 bytes
// -2: a fixed size of 1 byte
soyccan marked this conversation as resolved.
Show resolved Hide resolved
let memory_access = match op {
opcode::KECCAK256 | opcode::RETURN | opcode::REVERT => (1, 2, 0, 0),
opcode::CALLDATACOPY | opcode::CODECOPY | opcode::RETURNDATACOPY => (0, 0, 1, 3),
opcode::EXTCODECOPY => (0, 0, 2, 4),
opcode::MLOAD => (1, -1, 0, 0),
opcode::MSTORE => (0, 0, 1, -1),
opcode::MSTORE8 => (0, 0, 1, -2),
opcode::LOG0 | opcode::LOG1 | opcode::LOG2 | opcode::LOG3 | opcode::LOG4 => {
(1, 2, 0, 0)
}
opcode::CREATE | opcode::CREATE2 => (2, 3, 0, 0),
opcode::CALL | opcode::CALLCODE => (4, 5, 0, 0),
opcode::DELEGATECALL | opcode::STATICCALL => (3, 4, 0, 0),
_ => Default::default(),
};

let stack_len = stack.len();
let get_size = |stack_index| match stack_index {
-2 => Some(1),
-1 => Some(32),
0 => None,
1.. => Some(stack[stack_len - stack_index as usize].to()),
_ => panic!("invalid stack index"),
};

let (read_offset, read_size, write_offset, write_size) = (
get_size(memory_access.0),
get_size(memory_access.1),
get_size(memory_access.2),
get_size(memory_access.3),
);
(read_offset, read_size, write_offset, write_size)
}

/// Draw memory in memory pane
fn draw_memory<B: Backend>(
f: &mut Frame<B>,
Expand All @@ -877,33 +921,34 @@ Line::from(Span::styled("[t]: stack labels | [m]: memory decoding | [shift + j/k

// color memory words based on write/read
let mut word: Option<usize> = None;
let mut size: Option<usize> = None;
let mut color = None;
if let Instruction::OpCode(op) = debug_steps[current_step].instruction {
let stack_len = debug_steps[current_step].stack.len();
if stack_len > 0 {
let w = debug_steps[current_step].stack[stack_len - 1];
match op {
opcode::MLOAD => {
word = Some(w.to());
color = Some(Color::Cyan);
}
opcode::MSTORE => {
word = Some(w.to());
color = Some(Color::Red);
}
_ => {}
let (read_offset, read_size, write_offset, write_size) =
Tui::get_memory_access(op, &debug_steps[current_step].stack);
if read_offset.is_some() {
word = read_offset;
size = read_size;
color = Some(Color::Cyan);
} else if write_offset.is_some() {
word = write_offset;
size = write_size;
color = Some(Color::Red);
}
}
}

// color word on previous write op
if current_step > 0 {
let prev_step = current_step - 1;
let stack_len = debug_steps[prev_step].stack.len();
if let Instruction::OpCode(op) = debug_steps[prev_step].instruction {
if op == opcode::MSTORE {
let prev_top = debug_steps[prev_step].stack[stack_len - 1];
word = Some(prev_top.to());
let (_, _, write_offset, write_size) =
Tui::get_memory_access(op, &debug_steps[prev_step].stack);
if write_offset.is_some() {
word = write_offset;
size = write_size;
color = Some(Color::Green);
}
}
Expand All @@ -924,8 +969,11 @@ Line::from(Span::styled("[t]: stack labels | [m]: memory decoding | [shift + j/k
.map(|(j, byte)| {
Span::styled(
format!("{byte:02x} "),
if let (Some(w), Some(color)) = (word, color) {
if (i == w / 32 && j >= w % 32) || (i == w / 32 + 1 && j < w % 32) {
if let (Some(w), Some(size), Some(color)) = (word, size, color) {
if (i == w / 32 && j >= w % 32) ||
(i > w / 32 && i < (w + size - 1) / 32) ||
(i == (w + size - 1) / 32 && j <= (w + size - 1) % 32)
soyccan marked this conversation as resolved.
Show resolved Hide resolved
{
Style::default().fg(color)
} else if *byte == 0 {
Style::default().add_modifier(Modifier::DIM)
Expand Down