'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 {
|
pub fn parameters_size_field(&self) -> Uleb128 {
|
||||||
Uleb128(self.parameter_names.len() as u32)
|
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 {
|
impl Serializable for DebugInfoItem {
|
||||||
|
|
@ -316,7 +149,7 @@ impl DebugInfo {
|
||||||
|
|
||||||
/// A state machine that interpret a [`DebugInfoItem`].
|
/// A state machine that interpret a [`DebugInfoItem`].
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct DebugStateMachine<'a> {
|
pub struct DebugInfoReader<'a> {
|
||||||
debug_info: &'a DebugInfoItem,
|
debug_info: &'a DebugInfoItem,
|
||||||
pub pc: usize,
|
pub pc: usize,
|
||||||
pub address: u32,
|
pub address: u32,
|
||||||
|
|
@ -328,7 +161,7 @@ pub struct DebugStateMachine<'a> {
|
||||||
pub register_states: Vec<DebugRegState>,
|
pub register_states: Vec<DebugRegState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DebugStateMachine<'a> {
|
impl<'a> DebugInfoReader<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
debug_info: &'a DebugInfoItem,
|
debug_info: &'a DebugInfoItem,
|
||||||
//source_file_idx: Option<u32>,
|
//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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::DbgBytecode::*;
|
use super::DbgBytecode::*;
|
||||||
|
|
@ -574,4 +672,27 @@ mod test {
|
||||||
DbgBytecode::deserialize_from_slice(&advance_line.serialize_to_vec().unwrap()).unwrap()
|
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