'debug' serialization
This commit is contained in:
parent
bc3392d946
commit
f3fcb5b086
1 changed files with 290 additions and 169 deletions
|
|
@ -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<Uleb128p1>,
|
||||
debug_infos: Vec<DebugInfo>,
|
||||
) -> 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<DebugRegState>,
|
||||
}
|
||||
|
||||
impl<'a> DebugStateMachine<'a> {
|
||||
impl<'a> DebugInfoReader<'a> {
|
||||
pub fn new(
|
||||
debug_info: &'a DebugInfoItem,
|
||||
//source_file_idx: Option<u32>,
|
||||
|
|
@ -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<DbgBytecode>,
|
||||
line_start: u32,
|
||||
parameter_names: Vec<Uleb128p1>,
|
||||
|
||||
//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<u32>,
|
||||
//pub prologue_end: bool,
|
||||
//pub epilogue_begin: bool,
|
||||
register_states: Vec<DebugRegState>,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
impl DebugInfoBuilder {
|
||||
pub fn new(parameter_names: Vec<Uleb128p1>) -> 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<DebugInfoItem> {
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue