use super::*;
use crate::utils::iter::HasRestLen;
use std::mem::take;
use tracing::error;
#[derive(Clone)]
pub struct SymIter<'a> {
data: &'a [u8],
}
impl<'a> HasRestLen for SymIter<'a> {
fn rest_len(&self) -> usize {
self.data.len()
}
}
pub struct SymIterMut<'a> {
data: &'a mut [u8],
}
impl<'a> SymIterMut<'a> {
pub fn get_signature(&mut self) -> Result<[u8; 4], ParserError> {
let mut p = ParserMut::new(take(&mut self.data));
let sig = p.copy()?;
self.data = p.into_rest();
Ok(sig)
}
}
impl<'a> HasRestLen for SymIterMut<'a> {
fn rest_len(&self) -> usize {
self.data.len()
}
}
impl<'a> SymIter<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data }
}
pub fn skip_module_prefix(&mut self) {
if self.data.len() >= 4 {
self.data = &self.data[4..];
}
}
pub fn for_module_syms(data: &'a [u8]) -> Self {
Self {
data: if data.len() < 4 { &[] } else { &data[4..] },
}
}
pub fn get_signature(&mut self) -> Result<[u8; 4], ParserError> {
let mut p = Parser::new(self.data);
let sig = p.copy()?;
self.data = p.into_rest();
Ok(sig)
}
pub fn rest(&self) -> &'a [u8] {
self.data
}
pub fn one(data: &'a [u8]) -> Option<Sym<'a>> {
Self::new(data).next()
}
}
impl<'a> Iterator for SymIter<'a> {
type Item = Sym<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.data.is_empty() {
return None;
}
let mut p = Parser::new(self.data);
let record_len = p.u16().ok()?;
if record_len < 2 {
error!(
invalid_record_len = record_len,
iterator_pos = self.data.len(),
"type record has invalid len"
);
return None;
}
let kind = SymKind(p.u16().ok()?);
let record_data = p.bytes(record_len as usize - 2).ok()?;
self.data = p.into_rest();
Some(Sym {
kind,
data: record_data,
})
}
}
#[test]
fn test_sym_iter() {
#[rustfmt::skip]
let data: &[u8] = &[
6, 0, 0x4c, 0x11, 1, 2, 3, 4,
10, 0, 0x24, 0x11, b'b', b'o', b'o', b's', b't', 0,
0xf1, 0xf2,
10, 0, 0x24, 0x11, b'a', b'b', b'c', b'd', b'e', b'f', b'g', 0,
];
let mut i = SymIter::new(data);
assert_eq!(i.rest_len(), 0x20);
let s0 = i.next().unwrap();
assert_eq!(s0.kind, SymKind::S_BUILDINFO);
let s0_data = s0.parse().unwrap();
assert!(matches!(s0_data, SymData::BuildInfo(_)));
assert_eq!(i.rest_len(), 0x18);
let s1 = i.next().unwrap();
assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
match s1.parse() {
Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "boost"),
sd => panic!("wrong: {sd:?}"),
}
assert_eq!(i.rest_len(), 0xc);
let s1 = i.next().unwrap();
assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
match s1.parse() {
Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "abcdefg"),
sd => panic!("wrong: {sd:?}"),
}
assert_eq!(i.rest_len(), 0);
assert!(i.next().is_none());
}
impl<'a> SymIterMut<'a> {
pub fn new(data: &'a mut [u8]) -> Self {
Self { data }
}
pub fn rest(&self) -> &[u8] {
self.data
}
pub fn rest_mut(&mut self) -> &mut [u8] {
self.data
}
pub fn into_rest(self) -> &'a mut [u8] {
self.data
}
}
impl<'a> Iterator for SymIterMut<'a> {
type Item = SymMut<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.data.len() < 4 {
return None;
}
let d = core::mem::take(&mut self.data);
let mut p = Parser::new(d);
let record_len = p.u16().ok()?;
if record_len < 2 {
error!(
record_len,
iterator_len = self.data.len(),
"type record has invalid len"
);
self.data = d;
return None;
}
let kind = SymKind(p.u16().ok()?);
let (entire_record_data, hi) = d.split_at_mut(2 + record_len as usize);
self.data = hi;
let record_data = &mut entire_record_data[4..];
Some(SymMut {
kind,
data: record_data,
})
}
}