monistode_binutils/
symbols.rs

1use crate::executable::segments::flags::SegmentFlags;
2use crate::executable::segments::SegmentHeader;
3use crate::object_file::{SectionHeader, SymbolTableHeader};
4
5use super::address::Address;
6use super::serializable::*;
7
8#[derive(Debug, Clone)]
9pub struct Symbol {
10    pub name: String,
11    pub address: Address,
12}
13
14#[derive(Debug, Clone)]
15struct SymbolEntry {
16    section_id: u32,
17    offset: Address,
18    name_offset: u32,
19}
20
21#[derive(Debug, Clone)]
22pub struct SymbolTable {
23    entries: Vec<SymbolEntry>,
24    names: Vec<u8>,
25}
26
27impl SymbolTable {
28    pub fn new() -> Self {
29        SymbolTable {
30            entries: Vec::new(),
31            names: Vec::new(),
32        }
33    }
34
35    pub fn add_symbol(&mut self, section_id: u32, symbol: Symbol) {
36        let name_offset = self.names.len() as u32;
37        self.names.extend(symbol.name.as_bytes());
38        self.names.push(0); // null terminator
39
40        self.entries.push(SymbolEntry {
41            section_id,
42            offset: symbol.address,
43            name_offset,
44        });
45    }
46
47    pub fn serialize_as_section(&self) -> (SectionHeader, Vec<u8>) {
48        let mut data = Vec::new();
49
50        // Entries
51        for entry in &self.entries {
52            data.extend(entry.section_id.to_le_bytes());
53            data.extend((entry.offset.0 as u32).to_le_bytes());
54            data.extend(entry.name_offset.to_le_bytes());
55        }
56
57        // Names
58        data.extend(&self.names);
59
60        let header = SectionHeader::SymbolTable(SymbolTableHeader {
61            entry_count: self.entries.len() as u32,
62            names_length: self.names.len() as u32,
63        });
64
65        (header, data)
66    }
67
68    pub fn serialize_as_segment(&self) -> (SegmentHeader, Vec<u8>) {
69        let mut data = Vec::new();
70
71        // Entries
72        for entry in &self.entries {
73            data.extend(entry.section_id.to_le_bytes());
74            data.extend((entry.offset.0 as u32).to_le_bytes());
75            data.extend(entry.name_offset.to_le_bytes());
76        }
77
78        // Names
79        data.extend(&self.names);
80
81        let header = SegmentHeader {
82            // TODO do what rust does best
83            address_space_start: 0, // Special -> special section type
84            address_space_size: self.entries.len() as u64, // Since it's special, we can use this field
85            // for whatever
86            // Special -> disk_bit_count doesn't have to follow the rules either
87            disk_bit_count: data.len(),
88            flags: SegmentFlags {
89                executable: false,
90                writable: false,
91                readable: false,
92                special: true,
93            },
94        };
95
96        (header, data)
97    }
98
99    pub fn deserialize_section(
100        header: &SymbolTableHeader,
101        data: &[u8],
102    ) -> Result<(usize, Self), SerializationError> {
103        let required_size = (header.entry_count as usize * 12) + header.names_length as usize;
104        if data.len() < required_size {
105            return Err(SerializationError::DataTooShort);
106        }
107
108        let mut offset = 0;
109        let mut entries = Vec::new();
110
111        // Read entries
112        for _ in 0..header.entry_count {
113            if offset + 12 > data.len() {
114                return Err(SerializationError::DataTooShort);
115            }
116
117            let section_id = u32::from_le_bytes([
118                data[offset],
119                data[offset + 1],
120                data[offset + 2],
121                data[offset + 3],
122            ]);
123            offset += 4;
124
125            let addr = u32::from_le_bytes([
126                data[offset],
127                data[offset + 1],
128                data[offset + 2],
129                data[offset + 3],
130            ]) as usize;
131            offset += 4;
132
133            let name_offset = u32::from_le_bytes([
134                data[offset],
135                data[offset + 1],
136                data[offset + 2],
137                data[offset + 3],
138            ]);
139            offset += 4;
140
141            if name_offset >= header.names_length {
142                return Err(SerializationError::InvalidData);
143            }
144
145            entries.push(SymbolEntry {
146                section_id,
147                offset: Address(addr),
148                name_offset,
149            });
150        }
151
152        // Read names
153        if offset + header.names_length as usize > data.len() {
154            return Err(SerializationError::DataTooShort);
155        }
156        let names = data[offset..offset + header.names_length as usize].to_vec();
157
158        // Validate that all names are properly null-terminated
159        if names.len() > 0 {
160            if !names.iter().any(|&b| b == 0) {
161                return Err(SerializationError::InvalidData);
162            }
163        }
164
165        Ok((
166            offset + header.names_length as usize,
167            SymbolTable { entries, names },
168        ))
169    }
170
171    pub fn deserialize_segment(
172        header: &SegmentHeader,
173        data: &[u8],
174    ) -> Result<(usize, Self), SerializationError> {
175        let required_size = header.disk_bit_count as usize;
176        if data.len() < required_size {
177            return Err(SerializationError::DataTooShort);
178        }
179
180        let mut offset = 0;
181        let mut entries = Vec::new();
182
183        // Read entries
184        for _ in 0..header.address_space_size {
185            if offset + 12 > data.len() {
186                return Err(SerializationError::DataTooShort);
187            }
188
189            let section_id = u32::from_le_bytes([
190                data[offset],
191                data[offset + 1],
192                data[offset + 2],
193                data[offset + 3],
194            ]);
195            offset += 4;
196
197            let addr = u32::from_le_bytes([
198                data[offset],
199                data[offset + 1],
200                data[offset + 2],
201                data[offset + 3],
202            ]) as usize;
203            offset += 4;
204
205            let name_offset = u32::from_le_bytes([
206                data[offset],
207                data[offset + 1],
208                data[offset + 2],
209                data[offset + 3],
210            ]);
211            offset += 4;
212
213            if name_offset >= header.disk_bit_count as u32 - header.address_space_size as u32 * 12 {
214                return Err(SerializationError::InvalidData);
215            }
216
217            entries.push(SymbolEntry {
218                section_id,
219                offset: Address(addr),
220                name_offset,
221            });
222        }
223
224        // Read names
225        let names = data[offset..header.disk_bit_count as usize].to_vec();
226
227        // Validate that all names are properly null-terminated
228        if !names.iter().any(|&b| b == 0) {
229            return Err(SerializationError::InvalidData);
230        }
231
232        Ok((
233            header.disk_bit_count as usize,
234            SymbolTable { entries, names },
235        ))
236    }
237
238    pub fn get_symbols(&self, section_id: u32) -> Vec<Symbol> {
239        self.entries
240            .iter()
241            .filter(|entry| entry.section_id == section_id)
242            .map(|entry| {
243                let mut name = String::new();
244                let mut i = entry.name_offset as usize;
245                while i < self.names.len() && self.names[i] != 0 {
246                    name.push(self.names[i] as char);
247                    i += 1;
248                }
249                Symbol {
250                    name,
251                    address: Address(entry.offset.0),
252                }
253            })
254            .collect()
255    }
256}