use crate::util::ReadRaw as _;
use crate::Addr;
#[cfg(doc)]
use super::types::AddrData;
#[cfg(doc)]
use super::types::INFO_TYPE_LINE_TABLE_INFO;
const END_SEQUENCE: u8 = 0x00;
const SET_FILE: u8 = 0x01;
const ADVANCE_PC: u8 = 0x02;
const ADVANCE_LINE: u8 = 0x03;
const FIRST_SPECIAL: u8 = 0x04;
#[derive(Debug)]
pub enum RunResult {
Ok,
NewRow,
End,
}
#[derive(Debug)]
pub struct LineTableHeader {
pub min_delta: i64,
pub max_delta: i64,
pub first_line: u32,
}
impl LineTableHeader {
pub(super) fn parse(data: &mut &[u8]) -> Option<Self> {
let min_delta = data.read_i64_leb128()?;
let max_delta = data.read_i64_leb128()?;
let first_line = data.read_u64_leb128()?;
let header = Self {
min_delta,
max_delta,
first_line: first_line as u32,
};
Some(header)
}
}
#[derive(Clone, Debug)]
pub struct LineTableRow {
pub addr: Addr,
pub file_idx: u32,
pub file_line: u32,
}
impl LineTableRow {
pub(crate) fn from_header(header: &LineTableHeader, symaddr: Addr) -> Self {
Self {
addr: symaddr,
file_idx: 1,
file_line: header.first_line,
}
}
}
pub(crate) fn run_op(
row: &mut LineTableRow,
header: &LineTableHeader,
ops: &mut &[u8],
) -> Option<RunResult> {
let op = ops.read_u8()?;
match op {
END_SEQUENCE => Some(RunResult::End),
SET_FILE => {
let f = ops.read_u64_leb128()?;
row.file_idx = f as u32;
Some(RunResult::Ok)
}
ADVANCE_PC => {
let adv = ops.read_u64_leb128()?;
row.addr += adv;
Some(RunResult::NewRow)
}
ADVANCE_LINE => {
let adv = ops.read_i64_leb128()?;
row.file_line = (row.file_line as i64 + adv) as u32;
Some(RunResult::Ok)
}
_ => {
let adjusted = (op - FIRST_SPECIAL) as i64;
let range = header.max_delta - header.min_delta + 1;
if range == 0 {
return None
}
let line_delta = header.min_delta + (adjusted % range);
let addr_delta = adjusted / range;
let file_line = row.file_line as i32 + line_delta as i32;
row.file_line = file_line as u32;
row.addr += addr_delta as Addr;
Some(RunResult::NewRow)
}
}
}