diff --git a/androscalpel_serializer/src/debug.rs b/androscalpel_serializer/src/debug.rs index 4c868f9..8c4003b 100644 --- a/androscalpel_serializer/src/debug.rs +++ b/androscalpel_serializer/src/debug.rs @@ -57,173 +57,6 @@ impl DebugInfoItem { pub fn parameters_size_field(&self) -> Uleb128 { Uleb128(self.parameter_names.len() as u32) } - pub fn from_debug_infos( - line_start: Uleb128, - parameter_names: Vec, - debug_infos: Vec, - ) -> Self { - let mut bytecode = vec![]; - let mut address = 0; - let mut line = line_start.0; - let mut register_states = vec![]; - for dbg_info in debug_infos { - match dbg_info { - DebugInfo::DefLocal { addr, reg, val } => { - while register_states.len() < (reg + 1) as usize { - register_states.push(DebugRegState { - name_idx: None, - type_idx: None, - sig_idx: None, - in_scope: false, - }); - } - if addr != address { - let addr_diff = addr - address; - bytecode.push(DbgBytecode::AdvancePC { - addr_diff: Uleb128(addr_diff), - }); - address += addr_diff; - } - let mut old_val = register_states[reg as usize]; - let old_val_in_scope = old_val.in_scope; - old_val.in_scope = true; - if old_val_in_scope && old_val == val { - register_states[reg as usize].in_scope = true; - bytecode.push(DbgBytecode::RestartLocal { - register_num: Uleb128(reg), - }); - } else { - register_states[reg as usize] = val; - if val.sig_idx.is_some() { - bytecode.push(DbgBytecode::StartLocalExtended { - register_num: Uleb128(reg), - name_idx: if let Some(name_idx) = val.name_idx { - Uleb128p1(name_idx) - } else { - NO_INDEX - }, - type_idx: if let Some(type_idx) = val.type_idx { - Uleb128p1(type_idx) - } else { - NO_INDEX - }, - sig_idx: if let Some(sig_idx) = val.sig_idx { - Uleb128p1(sig_idx) - } else { - NO_INDEX - }, - }) - } else { - bytecode.push(DbgBytecode::StartLocal { - register_num: Uleb128(reg), - name_idx: if let Some(name_idx) = val.name_idx { - Uleb128p1(name_idx) - } else { - NO_INDEX - }, - type_idx: if let Some(type_idx) = val.type_idx { - Uleb128p1(type_idx) - } else { - NO_INDEX - }, - }) - } - } - } - DebugInfo::EndLocal { addr, reg } => { - while register_states.len() < (reg + 1) as usize { - register_states.push(DebugRegState { - name_idx: None, - type_idx: None, - sig_idx: None, - in_scope: false, - }); - } - if addr != address { - let addr_diff = addr - address; - bytecode.push(DbgBytecode::AdvancePC { - addr_diff: Uleb128(addr_diff), - }); - address += addr_diff; - } - bytecode.push(DbgBytecode::EndLocal { - register_num: Uleb128(reg), - }); - } - DebugInfo::PrologueEnd { addr } => { - if addr != address { - let addr_diff = addr - address; - bytecode.push(DbgBytecode::AdvancePC { - addr_diff: Uleb128(addr_diff), - }); - address += addr_diff; - } - bytecode.push(DbgBytecode::SetPrologueEnd); - } - DebugInfo::EpilogueBegin { addr } => { - if addr != address { - let addr_diff = addr - address; - bytecode.push(DbgBytecode::AdvancePC { - addr_diff: Uleb128(addr_diff), - }); - address += addr_diff; - } - bytecode.push(DbgBytecode::SetEpilogueBegin); - } - DebugInfo::SetSourceFile { - addr, - source_file_idx, - } => { - if addr != address { - let addr_diff = addr - address; - bytecode.push(DbgBytecode::AdvancePC { - addr_diff: Uleb128(addr_diff), - }); - address += addr_diff; - } - bytecode.push(DbgBytecode::SetFile { - name_idx: if let Some(source_file_idx) = source_file_idx { - Uleb128p1(source_file_idx) - } else { - NO_INDEX - }, - }); - } - DebugInfo::SetLineNumber { addr, line_num } => { - let mut line_diff = line_num as i32 - line as i32; - let mut addr_diff = addr - address; - if addr_diff > (0xff - 0x0a) / 15 { - bytecode.push(DbgBytecode::AdvancePC { - addr_diff: Uleb128(addr_diff), - }); - address = addr; - addr_diff = 0; - } - if !(-4..15 - 4).contains(&line_diff) { - bytecode.push(DbgBytecode::AdvanceLine { - line_diff: Sleb128(line_diff), - }); - line = line_num; - line_diff = 0; - } - let op = 0x0a + addr_diff as u8 * 15 + (line_diff + 4) as u8; - bytecode.push(DbgBytecode::SpecialOpcode(op)); - } - DebugInfo::EndOfData => { - bytecode.push(DbgBytecode::EndSequence); - break; - } - } - } - if bytecode.is_empty() || bytecode[bytecode.len() - 1] != DbgBytecode::EndSequence { - bytecode.push(DbgBytecode::EndSequence); - } - Self { - line_start, - parameter_names, - bytecode, - } - } } impl Serializable for DebugInfoItem { @@ -316,7 +149,7 @@ impl DebugInfo { /// A state machine that interpret a [`DebugInfoItem`]. #[derive(Debug, PartialEq, Eq, Clone)] -pub struct DebugStateMachine<'a> { +pub struct DebugInfoReader<'a> { debug_info: &'a DebugInfoItem, pub pc: usize, pub address: u32, @@ -328,7 +161,7 @@ pub struct DebugStateMachine<'a> { pub register_states: Vec, } -impl<'a> DebugStateMachine<'a> { +impl<'a> DebugInfoReader<'a> { pub fn new( debug_info: &'a DebugInfoItem, //source_file_idx: Option, @@ -537,6 +370,271 @@ impl<'a> DebugStateMachine<'a> { } } +/// A state machine that generate a [`DebugInfoItem`]. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct DebugInfoBuilder { + debug_infos: Vec, + line_start: u32, + parameter_names: Vec, + + //pub pc: usize, + address: u32, + line: u32, + // Those are registers described in the doc but not necessary in the end + //pub source_file_idx: Option, + //pub prologue_end: bool, + //pub epilogue_begin: bool, + register_states: Vec, + finished: bool, +} + +impl DebugInfoBuilder { + pub fn new(parameter_names: Vec) -> Self { + Self { + debug_infos: vec![], + line_start: 0, + parameter_names, + //pc: 0, + address: 0, + line: 0, + //source_file_idx, + //prologue_end: false, + //epilogue_begin: false, + //register_states: vec![ + // DebugRegState { + // name_idx: None, + // type_idx: None, + // sig_idx: None, + // in_scope: false, + // }; + // nb_reg + //], + register_states: vec![], // In the end, it's easier to grow this on the fly + finished: false, + } + } + + pub fn add_info(&mut self, info: &DebugInfo) -> Result<()> { + if self.finished { + return Err(Error::SerializationError( + "Cannot add more information: EndSequence has already been send".into(), + )); + } + match info { + DebugInfo::DefLocal { addr, reg, val } => { + if *addr < self.address { + return Err(Error::SerializationError(format!( + "The address register can only increase, \ + found 0x{addr:02x} while register is already \ + 0x{:02x}", + self.address + ))); + } + while self.register_states.len() < (reg + 1) as usize { + self.register_states.push(DebugRegState { + name_idx: None, + type_idx: None, + sig_idx: None, + in_scope: false, + }); + } + if *addr != self.address { + let addr_diff = *addr - self.address; + self.debug_infos.push(DbgBytecode::AdvancePC { + addr_diff: Uleb128(addr_diff), + }); + self.address += addr_diff; + } + let mut old_val = self.register_states[*reg as usize]; + let old_val_in_scope = old_val.in_scope; + old_val.in_scope = true; + if old_val_in_scope && old_val == *val { + self.register_states[*reg as usize].in_scope = true; + self.debug_infos.push(DbgBytecode::RestartLocal { + register_num: Uleb128(*reg), + }); + } else { + self.register_states[*reg as usize] = *val; + if val.sig_idx.is_some() { + self.debug_infos.push(DbgBytecode::StartLocalExtended { + register_num: Uleb128(*reg), + name_idx: if let Some(name_idx) = val.name_idx { + Uleb128p1(name_idx) + } else { + NO_INDEX + }, + type_idx: if let Some(type_idx) = val.type_idx { + Uleb128p1(type_idx) + } else { + NO_INDEX + }, + sig_idx: if let Some(sig_idx) = val.sig_idx { + Uleb128p1(sig_idx) + } else { + NO_INDEX + }, + }) + } else { + self.debug_infos.push(DbgBytecode::StartLocal { + register_num: Uleb128(*reg), + name_idx: if let Some(name_idx) = val.name_idx { + Uleb128p1(name_idx) + } else { + NO_INDEX + }, + type_idx: if let Some(type_idx) = val.type_idx { + Uleb128p1(type_idx) + } else { + NO_INDEX + }, + }) + } + } + Ok(()) + } + DebugInfo::EndLocal { addr, reg } => { + if *addr < self.address { + return Err(Error::SerializationError(format!( + "The address register can only increase, \ + found 0x{addr:02x} while register is already \ + 0x{:02x}", + self.address + ))); + } + while self.register_states.len() < (reg + 1) as usize { + self.register_states.push(DebugRegState { + name_idx: None, + type_idx: None, + sig_idx: None, + in_scope: false, + }); + } + if *addr != self.address { + let addr_diff = *addr - self.address; + self.debug_infos.push(DbgBytecode::AdvancePC { + addr_diff: Uleb128(addr_diff), + }); + self.address += addr_diff; + } + self.debug_infos.push(DbgBytecode::EndLocal { + register_num: Uleb128(*reg), + }); + Ok(()) + } + DebugInfo::PrologueEnd { addr } => { + if *addr < self.address { + return Err(Error::SerializationError(format!( + "The address register can only increase, \ + found 0x{addr:02x} while register is already \ + 0x{:02x}", + self.address + ))); + } + if *addr != self.address { + let addr_diff = *addr - self.address; + self.debug_infos.push(DbgBytecode::AdvancePC { + addr_diff: Uleb128(addr_diff), + }); + self.address += addr_diff; + } + self.debug_infos.push(DbgBytecode::SetPrologueEnd); + Ok(()) + } + DebugInfo::EpilogueBegin { addr } => { + if *addr < self.address { + return Err(Error::SerializationError(format!( + "The address register can only increase, \ + found 0x{addr:02x} while register is already \ + 0x{:02x}", + self.address + ))); + } + if *addr != self.address { + let addr_diff = *addr - self.address; + self.debug_infos.push(DbgBytecode::AdvancePC { + addr_diff: Uleb128(addr_diff), + }); + self.address += addr_diff; + } + self.debug_infos.push(DbgBytecode::SetEpilogueBegin); + Ok(()) + } + DebugInfo::SetLineNumber { addr, line_num } => { + if *addr < self.address { + return Err(Error::SerializationError(format!( + "The address register can only increase, \ + found 0x{addr:02x} while register is already \ + 0x{:02x}", + self.address + ))); + } + if self.line_start == 0 { + self.line_start = *line_num; + self.line = *line_num; + } + let mut line_diff = *line_num as i32 - self.line as i32; + let mut addr_diff = addr - self.address; + if addr_diff > (0xff - 0x0a) / 15 { + self.debug_infos.push(DbgBytecode::AdvancePC { + addr_diff: Uleb128(addr_diff), + }); + self.address = *addr; + addr_diff = 0; + } + if !(-4..15 - 4).contains(&line_diff) { + self.debug_infos.push(DbgBytecode::AdvanceLine { + line_diff: Sleb128(line_diff), + }); + self.line = *line_num; + line_diff = 0; + } + let op = 0x0a + addr_diff as u8 * 15 + (line_diff + 4) as u8; + self.debug_infos.push(DbgBytecode::SpecialOpcode(op)); + self.address += addr_diff; + self.line = (self.line as i32 + line_diff) as u32; + Ok(()) + } + DebugInfo::SetSourceFile { + addr, + source_file_idx, + } => { + if *addr != self.address { + let addr_diff = *addr - self.address; + self.debug_infos.push(DbgBytecode::AdvancePC { + addr_diff: Uleb128(addr_diff), + }); + self.address += addr_diff; + } + self.debug_infos.push(DbgBytecode::SetFile { + name_idx: if let Some(source_file_idx) = source_file_idx { + Uleb128p1(*source_file_idx) + } else { + NO_INDEX + }, + }); + Ok(()) + } + DebugInfo::EndOfData => { + self.finished = true; + Ok(()) + } + } + } + + /// If they are no debug information, return None, else compute and return the [`DebugInfoItem`]. + pub fn build(self) -> Option { + if self.debug_infos.is_empty() && self.parameter_names.iter().all(|&idx| idx == NO_INDEX) { + None + } else { + Some(DebugInfoItem { + line_start: Uleb128(self.line_start), + parameter_names: self.parameter_names, + bytecode: self.debug_infos, + }) + } + } +} + #[cfg(test)] mod test { use super::DbgBytecode::*; @@ -574,4 +672,27 @@ mod test { DbgBytecode::deserialize_from_slice(&advance_line.serialize_to_vec().unwrap()).unwrap() ); } + + #[test] + fn test_get_expl_debug() { + const RAW_DEBUG: [u8; 10] = [23, 0, 14, 135, 3, 0, 16, 2, 150, 0]; + let debug = DebugInfoItem::deserialize_from_slice(&RAW_DEBUG).unwrap(); + let mut reader = DebugInfoReader::new(&debug); + let mut list_info = vec![]; + loop { + list_info.push(reader.next_info()); + if list_info.last() == Some(&DebugInfo::EndOfData) { + break; + } + } + let mut builder = DebugInfoBuilder::new(debug.parameter_names.clone()); + for info in list_info { + builder.add_info(&info).unwrap(); + } + let debug_computed = builder.build().unwrap(); + assert_eq!( + &RAW_DEBUG, + &(debug_computed.serialize_to_vec().unwrap()).as_slice() + ); + } }