ms_pdb/syms/iter.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
use super::*;
use crate::utils::iter::HasRestLen;
use std::mem::take;
use tracing::error;
/// Parses [`Sym`] records from a symbol stream.
#[derive(Clone)]
pub struct SymIter<'a> {
data: &'a [u8],
}
impl<'a> HasRestLen for SymIter<'a> {
fn rest_len(&self) -> usize {
self.data.len()
}
}
/// Parses [`SymMut`] records from a symbol stream.
///
/// This iterator allows you to modify the payload of a symbol record but not to change its length
/// or its kind.
pub struct SymIterMut<'a> {
data: &'a mut [u8],
}
impl<'a> SymIterMut<'a> {
/// Parses the 4-byte CodeView signature that is at the start of a module symbol stream.
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> {
/// Creates a new symbol iterator.
pub fn new(data: &'a [u8]) -> Self {
Self { data }
}
/// Parses the 4-byte CodeView signature that is at the start of a module symbol stream.
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)
}
/// The remaining unparsed bytes in the symbol stream.
pub fn rest(&self) -> &'a [u8] {
self.data
}
/// Parses a single record from `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] = &[
// record 0, total size = 8
/* 0x0000 */ 6, 0, // size
/* 0x0002 */ 0x4c, 0x11, // S_BUILDINFO
/* 0x0004 */ 1, 2, 3, 4, // payload (ItemId)
// record 1, total size = 12
/* 0x0008 */ 10, 0, // size
/* 0x000a */ 0x24, 0x11, // S_UNAMESPACE
/* 0x000c */ b'b', b'o', b'o', b's', // payload (6 bytes)
/* 0x0010 */ b't', 0,
/* 0x0012 */ 0xf1, 0xf2, // alignment padding (inside payload)
// record 2, total size = 12
/* 0x0014 */ 10, 0, // size
/* 0x0016 */ 0x24, 0x11, // S_UNAMESPACE
/* 0x0018 */ b'a', b'b', b'c', b'd', // payload
/* 0x001c */ b'e', b'f', b'g', 0, // no alignment padding
/* 0x0020 : end */
];
let mut i = SymIter::new(data);
// parse record 0
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(_)));
// parse record 1
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:?}"),
}
// parse record 2
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:?}"),
}
// end
assert_eq!(i.rest_len(), 0);
assert!(i.next().is_none());
}
impl<'a> SymIterMut<'a> {
/// Creates a new symbol iterator.
pub fn new(data: &'a mut [u8]) -> Self {
Self { data }
}
/// The remaining unparsed bytes in the symbol stream.
pub fn rest(&self) -> &[u8] {
self.data
}
/// The remaining unparsed bytes in the symbol stream, with mutable access.
pub fn rest_mut(&mut self) -> &mut [u8] {
self.data
}
/// Converts this iterator into a mutable reference to the unparsed bytes in the symbol stream.
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;
}
// We steal self.data because it is the only way that split_at_mut() can work.
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,
})
}
}