use crate::{
jump::{relocate, Jump, JumpTable},
Error, Result, BUFFER_LIMIT,
};
impl JumpTable {
pub fn shift_pc(&mut self, start: u16, offset: u16) -> Result<()> {
tracing::trace!("shift pc from 0x{start:x} with offset={offset}");
self.shift_label_pc(start, offset)?;
self.shift_label_target(start, offset)?;
self.shift_func_target(start, offset)?;
Ok(())
}
pub fn shift_label_pc(&mut self, start: u16, offset: u16) -> Result<()> {
self.jump = self
.jump
.iter()
.map(|(k, v)| {
let mut k = *k;
if k > start {
tracing::trace!(
"shift {v:x?} pc with offset={offset}: 0x{k:x}(0x{start:x}) -> 0x{:x}",
k + offset
);
k += offset;
if k > BUFFER_LIMIT as u16 {
return Err(Error::InvalidPC(k as usize));
}
}
Ok((k, v.clone()))
})
.collect::<Result<_>>()?;
Ok(())
}
pub fn shift_targets(&mut self) -> Result<()> {
let mut total_offset = 0;
self.jump
.clone()
.keys()
.try_for_each(|original_pc| -> Result<()> {
let pc = original_pc + total_offset;
let offset = relocate::offset(pc)?;
total_offset += offset;
self.shift_target(pc, offset)
})
}
pub fn shift_target(&mut self, ptr: u16, offset: u16) -> Result<()> {
self.code.shift(offset);
self.shift_label_target(ptr, offset)?;
self.shift_func_target(ptr, offset)
}
pub fn shift_func_target(&mut self, start: u16, offset: u16) -> Result<()> {
self.func.iter_mut().try_for_each(|(k, v)| {
if *v > start {
tracing::trace!(
"shift Func({k}) target with offset={offset}: 0x{v:x}(0x{start:x}) -> 0x{:x}",
*v + offset
);
*v += offset;
if *v > BUFFER_LIMIT as u16 {
return Err(Error::InvalidPC(*v as usize));
}
}
Ok(())
})?;
Ok(())
}
pub fn shift_label_target(&mut self, ptr: u16, offset: u16) -> Result<()> {
self.jump.iter_mut().try_for_each(|(pc, target)| {
if let Jump::Label(label) = target {
if *label > ptr {
tracing::trace!(
"shift Label(pc=0x{pc:x}) target with offset={offset} 0x{label:x}(0x{ptr:x}) -> 0x{:x}",
*label + offset
);
*label += offset;
}
}
Ok(())
})
}
}