ms_codeview/syms/
builder.rs

1//! Supports building new symbol streams
2
3use super::SymKind;
4use crate::encoder::Encoder;
5use crate::types::TypeIndex;
6use bstr::BStr;
7
8/// Writes symbol records into a buffer.
9#[derive(Default)]
10pub struct SymBuilder {
11    /// Contains the symbol stream
12    pub buffer: Vec<u8>,
13}
14
15impl SymBuilder {
16    /// Creates a new empty symbol stream builder.
17    pub fn new() -> Self {
18        Self { buffer: Vec::new() }
19    }
20
21    /// Consumes this builder and returns the symbol stream.
22    pub fn finish(self) -> Vec<u8> {
23        self.buffer
24    }
25
26    /// Starts adding a new record to the builder.
27    pub fn record(&mut self, kind: SymKind) -> RecordBuilder<'_> {
28        let record_start = self.buffer.len();
29        self.buffer.extend_from_slice(&[0, 0]); // placeholder for record length
30        self.buffer.extend_from_slice(&kind.0.to_le_bytes());
31        RecordBuilder {
32            enc: Encoder::new(&mut self.buffer),
33            record_start,
34        }
35    }
36
37    /// Adds an `S_UDT` record.
38    pub fn udt(&mut self, ty: TypeIndex, name: &BStr) {
39        let mut r = self.record(SymKind::S_UDT);
40        r.enc.u32(ty.0);
41        r.enc.strz(name);
42    }
43
44    /// Adds an `S_PUB32` record.
45    pub fn pub32(&mut self, flags: u32, offset: u32, segment: u16, name: &str) {
46        let mut r = self.record(SymKind::S_PUB32);
47        r.enc.u32(flags);
48        r.enc.u32(offset);
49        r.enc.u16(segment);
50        r.enc.strz(name.into());
51    }
52}
53
54/// State for writing a single record. When this is dropped, it will terminate the record.
55pub struct RecordBuilder<'a> {
56    /// Encoder which can write the payload of the current record.
57    pub enc: Encoder<'a>,
58    /// Byte offset of the start of the current record. We use this to patch the record length
59    /// when we're done writing the record.
60    record_start: usize,
61}
62
63impl<'a> Drop for RecordBuilder<'a> {
64    fn drop(&mut self) {
65        // Align the buffer to a 4-byte boundary
66        match self.enc.buf.len() & 3 {
67            1 => self.enc.buf.push(0xf1),
68            2 => self.enc.buf.extend_from_slice(&[0xf1, 0xf2]),
69            3 => self.enc.buf.extend_from_slice(&[0xf1, 0xf2, 0xf3]),
70            _ => {}
71        }
72
73        let record_len = self.enc.buf.len() - self.record_start - 2;
74        let record_field = &mut self.enc.buf[self.record_start..];
75        record_field[0] = record_len as u8;
76        record_field[1] = (record_len >> 8) as u8;
77    }
78}