use std::collections::HashMap;
use deku::ctx::Endian;
use log::{debug, error};
use crate::deref::Deref;
use crate::gdb::read_memory;
use crate::mi::{INSTRUCTION_LEN, data_disassemble, data_read_memory_bytes};
use crate::register::RegisterStorage;
use crate::{PtrSize, State, Written};
pub fn recv_exec_result_memory(state: &mut State, memory: &String) {
if state.written.is_empty() {
return;
}
let last_written = state.written.pop_front().unwrap();
match last_written {
Written::RegisterValue((base_reg, _begin)) => {
debug!("new register val for {base_reg}");
let thirty = state.ptr_size == PtrSize::Size32;
let (data, _) = read_memory(memory);
for RegisterStorage { name: _, register, deref } in &mut state.registers {
if let Some(reg) = register
&& reg.number == base_reg
{
let (val, len) = if thirty {
let outer = if let Ok(val) = u32::from_str_radix(&data["contents"], 16) {
if state.endian.unwrap() == Endian::Big {
val.to_le()
} else {
val.to_be()
}
} else {
error!("Requested to many bytes for 32 bit processor");
return;
};
(u64::from(outer), 4)
} else {
let mut val = u64::from_str_radix(&data["contents"], 16).unwrap();
if state.endian.unwrap() == Endian::Big {
val = val.to_le();
} else {
val = val.to_be();
}
(val, 8)
};
if deref.try_push(val) {
let mut is_code = false;
if let Some(mm) = &state.memory_map {
for r in mm {
let is_path =
r.is_path(state.filepath.as_ref().unwrap().to_str().unwrap());
if r.contains(val) && (is_path || r.is_exec()) {
state
.next_write
.push(data_disassemble(val as usize, INSTRUCTION_LEN));
state.written.push_back(Written::SymbolAtAddrRegister((
reg.number.clone(),
val,
)));
is_code = true;
break;
}
}
}
if val > 0xff {
let bytes = val.to_le_bytes();
if bytes.iter().all(|a| {
a.is_ascii_alphabetic()
|| a.is_ascii_graphic()
|| a.is_ascii_whitespace()
}) {
let addr = data["begin"].strip_prefix("0x").unwrap().to_string();
let addr = u64::from_str_radix(&addr, 16).unwrap();
state.next_write.push(data_read_memory_bytes(addr + len, 0, len));
state
.written
.push_back(Written::RegisterValue((reg.number.clone(), val)));
return;
}
}
if !is_code && val != 0 {
debug!("register deref: trying to read: {val:02x}");
state.next_write.push(data_read_memory_bytes(val, 0, len));
state
.written
.push_back(Written::RegisterValue((reg.number.clone(), val)));
}
}
break;
}
}
}
Written::Stack(Some(begin)) => {
let (data, _) = read_memory(memory);
debug!("stack: {data:02x?}");
update_stack(data, state, begin);
}
Written::Stack(None) => {
let (data, begin) = read_memory(memory);
debug!("stack: {data:02x?}");
update_stack(data, state, begin);
}
Written::Memory => {
let (data, begin) = read_memory(memory);
debug!("memory: ({begin:02x?}, {data:02x?}");
let hex = hex::decode(&data["contents"]).unwrap();
state.hexdump = Some((u64::from_str_radix(&begin, 16).unwrap(), hex));
}
_ => {
error!("unexpected Written: {last_written:?}");
}
}
}
fn update_stack(data: HashMap<String, String>, state: &mut State, begin: String) {
let (val, len) = if state.ptr_size == PtrSize::Size32 {
let mut val = u32::from_str_radix(&data["contents"], 16).unwrap();
if state.endian.unwrap() == Endian::Big {
val = val.to_le();
} else {
val = val.to_be();
}
(u64::from(val), 4)
} else {
let mut val = u64::from_str_radix(&data["contents"], 16).unwrap();
if state.endian.unwrap() == Endian::Big {
val = val.to_le();
} else {
val = val.to_be();
}
(val, 8)
};
let key = u64::from_str_radix(&begin, 16).unwrap();
let deref = state.stack.entry(key).or_insert(Deref::new());
let inserted = deref.try_push(val);
if inserted && val != 0 {
if let Some(mm) = &state.memory_map {
for r in mm {
let is_path = r.is_path(state.filepath.as_ref().unwrap().to_str().unwrap());
if r.contains(val) && (is_path || r.is_exec()) {
debug!("stack deref: trying to read as asm: {val:02x}");
state.next_write.push(data_disassemble(val as usize, INSTRUCTION_LEN));
state.written.push_back(Written::SymbolAtAddrStack(begin.clone()));
return;
}
}
}
if val > 0xff {
let bytes = val.to_le_bytes();
if bytes
.iter()
.all(|a| a.is_ascii_alphabetic() || a.is_ascii_graphic() || a.is_ascii_whitespace())
{
let addr = data["begin"].strip_prefix("0x").unwrap().to_string();
let addr = u64::from_str_radix(&addr, 16).unwrap();
state.next_write.push(data_read_memory_bytes(addr + len, 0, len));
state.written.push_back(Written::Stack(Some(begin)));
return;
}
}
debug!("stack deref: trying to read as data: {val:02x}");
state.next_write.push(data_read_memory_bytes(val, 0, len));
state.written.push_back(Written::Stack(Some(begin)));
}
}