ds_decomp/config/
symbol.rs

1use std::{
2    backtrace::Backtrace,
3    collections::{BTreeMap, HashMap, btree_map, hash_map},
4    fmt::Display,
5    io::{self, BufRead, BufReader, BufWriter, Write},
6    num::ParseIntError,
7    ops::Range,
8    path::Path,
9    slice,
10};
11
12use snafu::{Snafu, ensure};
13
14use crate::{
15    analysis::{functions::Function, jump_table::JumpTable},
16    util::{
17        io::{FileError, create_file, open_file},
18        parse::parse_u32,
19    },
20};
21
22use super::{ParseContext, config::Config, iter_attributes, module::ModuleKind};
23
24pub struct SymbolMaps {
25    symbol_maps: BTreeMap<ModuleKind, SymbolMap>,
26}
27
28#[derive(Debug, Snafu)]
29pub enum SymbolMapsParseError {
30    #[snafu(transparent)]
31    SymbolMapParse { source: SymbolMapParseError },
32}
33
34#[derive(Debug, Snafu)]
35pub enum SymbolMapsWriteError {
36    #[snafu(display("Symbol map not found for {module}:\n{backtrace}"))]
37    SymbolMapNotFound { module: ModuleKind, backtrace: Backtrace },
38    #[snafu(transparent)]
39    SymbolMapWrite { source: SymbolMapWriteError },
40}
41
42impl SymbolMaps {
43    pub fn new() -> Self {
44        Self { symbol_maps: BTreeMap::new() }
45    }
46
47    pub fn get(&self, module: ModuleKind) -> Option<&SymbolMap> {
48        self.symbol_maps.get(&module)
49    }
50
51    pub fn get_mut(&mut self, module: ModuleKind) -> &mut SymbolMap {
52        self.symbol_maps.entry(module).or_insert_with(SymbolMap::new)
53    }
54
55    pub fn from_config<P: AsRef<Path>>(config_path: P, config: &Config) -> Result<Self, SymbolMapsParseError> {
56        let config_path = config_path.as_ref();
57
58        let mut symbol_maps = SymbolMaps::new();
59        symbol_maps.get_mut(ModuleKind::Arm9).load(config_path.join(&config.main_module.symbols))?;
60        for autoload in &config.autoloads {
61            symbol_maps.get_mut(ModuleKind::Autoload(autoload.kind)).load(config_path.join(&autoload.module.symbols))?;
62        }
63        for overlay in &config.overlays {
64            symbol_maps.get_mut(ModuleKind::Overlay(overlay.id)).load(config_path.join(&overlay.module.symbols))?;
65        }
66
67        Ok(symbol_maps)
68    }
69
70    pub fn to_files<P: AsRef<Path>>(&self, config: &Config, config_path: P) -> Result<(), SymbolMapsWriteError> {
71        let config_path = config_path.as_ref();
72        self.get(ModuleKind::Arm9)
73            .ok_or_else(|| SymbolMapNotFoundSnafu { module: ModuleKind::Arm9 }.build())?
74            .to_file(config_path.join(&config.main_module.symbols))?;
75        for autoload in &config.autoloads {
76            let module = ModuleKind::Autoload(autoload.kind);
77            self.get(module)
78                .ok_or_else(|| SymbolMapNotFoundSnafu { module }.build())?
79                .to_file(config_path.join(&autoload.module.symbols))?;
80        }
81        for overlay in &config.overlays {
82            let module = ModuleKind::Overlay(overlay.id);
83            self.get(module)
84                .ok_or_else(|| SymbolMapNotFoundSnafu { module }.build())?
85                .to_file(config_path.join(&overlay.module.symbols))?;
86        }
87
88        Ok(())
89    }
90
91    pub fn iter(&self) -> impl Iterator<Item = (ModuleKind, &'_ SymbolMap)> {
92        self.symbol_maps.iter().map(|(module, symbol_map)| (*module, symbol_map))
93    }
94
95    pub fn iter_mut(&mut self) -> impl Iterator<Item = (ModuleKind, &'_ mut SymbolMap)> {
96        self.symbol_maps.iter_mut().map(|(module, symbol_map)| (*module, symbol_map))
97    }
98
99    pub fn find_symbols_by_name(&self, name: &str) -> impl Iterator<Item = (ModuleKind, SymbolIndex, &Symbol)> {
100        self.symbol_maps.iter().flat_map(|(module, symbol_map)| {
101            symbol_map
102                .for_name(name)
103                .into_iter()
104                .flat_map(move |symbols| symbols.map(|(index, symbol)| (*module, index, symbol)))
105        })
106    }
107}
108
109#[derive(Clone, Copy, PartialEq, Eq)]
110pub struct SymbolIndex(usize);
111
112pub struct SymbolMap {
113    symbols: Vec<Symbol>,
114    symbols_by_address: BTreeMap<u32, Vec<SymbolIndex>>,
115    symbols_by_name: HashMap<String, Vec<SymbolIndex>>,
116}
117
118#[derive(Debug, Snafu)]
119pub enum SymbolMapParseError {
120    #[snafu(transparent)]
121    File { source: FileError },
122    #[snafu(transparent)]
123    Io { source: io::Error },
124    #[snafu(transparent)]
125    SymbolParse { source: SymbolParseError },
126}
127
128#[derive(Debug, Snafu)]
129pub enum SymbolMapWriteError {
130    #[snafu(transparent)]
131    File { source: FileError },
132    #[snafu(transparent)]
133    Io { source: io::Error },
134}
135
136#[derive(Debug, Snafu)]
137pub enum SymbolMapError {
138    #[snafu(display("multiple symbols at {address:#010x}: {name}, {other_name}:\n{backtrace}"))]
139    MultipleSymbols { address: u32, name: String, other_name: String, backtrace: Backtrace },
140    #[snafu(display("multiple symbols with name '{name}': {old_address:#010x}, {new_address:#010x}:\n{backtrace}"))]
141    DuplicateName { name: String, new_address: u32, old_address: u32, backtrace: Backtrace },
142    #[snafu(display("no symbol at {address:#010x} to rename to '{new_name}':\n{backtrace}"))]
143    NoSymbolToRename { address: u32, new_name: String, backtrace: Backtrace },
144    #[snafu(display("there must be exactly one symbol at {address:#010x} to rename to '{new_name}':\n{backtrace}"))]
145    RenameMultiple { address: u32, new_name: String, backtrace: Backtrace },
146}
147
148impl SymbolMap {
149    pub fn new() -> Self {
150        Self::from_symbols(vec![])
151    }
152
153    pub fn from_symbols(symbols: Vec<Symbol>) -> Self {
154        let mut symbols_by_address = BTreeMap::<u32, Vec<_>>::new();
155        let mut symbols_by_name = HashMap::<String, Vec<_>>::new();
156
157        for (index, symbol) in symbols.iter().enumerate() {
158            symbols_by_address.entry(symbol.addr).or_default().push(SymbolIndex(index));
159            symbols_by_name.entry(symbol.name.clone()).or_default().push(SymbolIndex(index));
160        }
161
162        Self { symbols, symbols_by_address, symbols_by_name }
163    }
164
165    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, SymbolMapParseError> {
166        let mut symbol_map = Self::new();
167        symbol_map.load(path)?;
168        Ok(symbol_map)
169    }
170
171    pub fn load<P: AsRef<Path>>(&mut self, path: P) -> Result<(), SymbolMapParseError> {
172        let path = path.as_ref();
173        let mut context = ParseContext { file_path: path.to_str().unwrap().to_string(), row: 0 };
174
175        let file = open_file(path)?;
176        let reader = BufReader::new(file);
177
178        for line in reader.lines() {
179            context.row += 1;
180
181            let line = line?;
182            let comment_start = line.find("//").unwrap_or(line.len());
183            let line = &line[..comment_start];
184
185            let Some(symbol) = Symbol::parse(line, &context)? else { continue };
186            self.add(symbol);
187        }
188        Ok(())
189    }
190
191    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), SymbolMapWriteError> {
192        let path = path.as_ref();
193
194        let file = create_file(path)?;
195        let mut writer = BufWriter::new(file);
196
197        for indices in self.symbols_by_address.values() {
198            for &index in indices {
199                let symbol = &self.symbols[index.0];
200                if symbol.should_write() {
201                    writeln!(writer, "{symbol}")?;
202                }
203            }
204        }
205
206        Ok(())
207    }
208
209    pub fn for_address(&self, address: u32) -> Option<impl DoubleEndedIterator<Item = (SymbolIndex, &Symbol)>> {
210        Some(self.symbols_by_address.get(&address)?.iter().map(|&i| (i, &self.symbols[i.0])))
211    }
212
213    pub fn by_address(&self, address: u32) -> Result<Option<(SymbolIndex, &Symbol)>, SymbolMapError> {
214        let Some(mut symbols) = self.for_address(address) else {
215            return Ok(None);
216        };
217        let (index, symbol) = symbols.next().unwrap();
218        if let Some((_, other)) = symbols.next() {
219            return MultipleSymbolsSnafu { address, name: symbol.name.clone(), other_name: other.name.clone() }.fail();
220        }
221        Ok(Some((index, symbol)))
222    }
223
224    pub fn first_at_address(&self, address: u32) -> Option<(SymbolIndex, &Symbol)> {
225        self.for_address(address)?.next()
226    }
227
228    pub fn for_name(&self, name: &str) -> Option<impl DoubleEndedIterator<Item = (SymbolIndex, &Symbol)>> {
229        Some(self.symbols_by_name.get(name)?.iter().map(|&i| (i, &self.symbols[i.0])))
230    }
231
232    pub fn by_name(&self, name: &str) -> Result<Option<(SymbolIndex, &Symbol)>, SymbolMapError> {
233        let Some(mut symbols) = self.for_name(name) else {
234            return Ok(None);
235        };
236        let (index, symbol) = symbols.next().unwrap();
237        if let Some((_, other)) = symbols.next() {
238            return DuplicateNameSnafu { name, new_address: symbol.addr, old_address: other.addr }.fail();
239        }
240        Ok(Some((index, symbol)))
241    }
242
243    pub fn iter_by_address(&self, range: Range<u32>) -> SymbolIterator {
244        SymbolIterator { symbols_by_address: self.symbols_by_address.range(range), indices: [].iter(), symbols: &self.symbols }
245    }
246
247    /// Returns the first symbol before the given address, or multiple symbols if they are at the same address.
248    pub fn first_symbol_before(&self, max_address: u32) -> Option<Vec<(SymbolIndex, &Symbol)>> {
249        self.symbols_by_address.range(0..=max_address).rev().find_map(|(_, indices)| {
250            let symbols = indices
251                .iter()
252                .filter_map(|&i| {
253                    let symbol = &self.symbols[i.0];
254                    symbol.is_external().then_some((i, symbol))
255                })
256                .collect::<Vec<_>>();
257            (!symbols.is_empty()).then_some(symbols)
258        })
259    }
260
261    /// Returns the first symbol after the given address, or multiple symbols if they are at the same address.
262    pub fn first_symbol_after(&self, min_address: u32) -> Option<Vec<(SymbolIndex, &Symbol)>> {
263        self.symbols_by_address.range(min_address + 1..).find_map(|(_, indices)| {
264            let symbols = indices
265                .iter()
266                .filter_map(|&i| {
267                    let symbol = &self.symbols[i.0];
268                    symbol.is_external().then_some((i, symbol))
269                })
270                .collect::<Vec<_>>();
271            (!symbols.is_empty()).then_some(symbols)
272        })
273    }
274
275    pub fn iter(&self) -> impl Iterator<Item = &'_ Symbol> {
276        self.symbols_by_address.values().flat_map(|indices| indices.iter()).map(|&i| &self.symbols[i.0])
277    }
278
279    pub fn indices_by_address(&self) -> impl Iterator<Item = &SymbolIndex> {
280        self.symbols_by_address.values().flat_map(|indices| indices.iter())
281    }
282
283    pub fn get(&self, index: SymbolIndex) -> Option<&Symbol> {
284        self.symbols.get(index.0)
285    }
286
287    pub fn get_mut(&mut self, index: SymbolIndex) -> Option<&mut Symbol> {
288        self.symbols.get_mut(index.0)
289    }
290
291    /// Returns the symbol containing the given address and the symbol's size.
292    pub fn get_symbol_containing(&self, addr: u32, section_end: u32) -> Result<Option<(&Symbol, u32)>, SymbolMapError> {
293        let Some(symbols) = self.first_symbol_before(addr) else {
294            return Ok(None);
295        };
296        let (_, symbol) = symbols.first().unwrap();
297        let Some(symbols) = self.first_symbol_after(symbol.addr) else {
298            return Ok(Some((symbol, symbol.size(section_end))));
299        };
300        let next_symbol = symbols.first().unwrap().1;
301
302        Ok(Some((symbol, symbol.size(next_symbol.addr.min(section_end)))))
303    }
304
305    pub fn add(&mut self, symbol: Symbol) -> (SymbolIndex, &Symbol) {
306        let index = SymbolIndex(self.symbols.len());
307        self.symbols_by_address.entry(symbol.addr).or_default().push(index);
308        self.symbols_by_name.entry(symbol.name.clone()).or_default().push(index);
309        self.symbols.push(symbol);
310
311        (index, self.symbols.last().unwrap())
312    }
313
314    pub fn add_if_new_address(&mut self, symbol: Symbol) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
315        if self.symbols_by_address.contains_key(&symbol.addr) {
316            Ok(self.by_address(symbol.addr)?.unwrap())
317        } else {
318            Ok(self.add(symbol))
319        }
320    }
321
322    pub fn get_function(&self, address: u32) -> Result<Option<(SymFunction, &Symbol)>, SymbolMapError> {
323        let Some(symbols) = self.for_address(address & !1) else {
324            return Ok(None);
325        };
326        let mut symbols = symbols.filter(|(_, sym)| matches!(sym.kind, SymbolKind::Function(_)));
327        let Some((_, symbol)) = symbols.next() else {
328            return Ok(None);
329        };
330        if let Some((_, other)) = symbols.next() {
331            return MultipleSymbolsSnafu { address, name: symbol.name.clone(), other_name: other.name.clone() }.fail();
332        }
333
334        Ok(match symbol.kind {
335            SymbolKind::Function(function) => Some((function, symbol)),
336            _ => None,
337        })
338    }
339
340    pub fn get_function_mut(&mut self, address: u32) -> Result<Option<&mut Symbol>, SymbolMapError> {
341        let Some(symbols) = self.symbols_by_address.get_mut(&(address & !1)) else {
342            return Ok(None);
343        };
344
345        let mut symbols = symbols.iter().filter(|i| matches!(self.symbols[i.0].kind, SymbolKind::Function(_)));
346        let Some(index) = symbols.next() else {
347            return Ok(None);
348        };
349        if let Some(other_index) = symbols.next() {
350            let symbol = &self.symbols[index.0];
351            let other = &self.symbols[other_index.0];
352            return MultipleSymbolsSnafu { address, name: symbol.name.clone(), other_name: other.name.clone() }.fail();
353        }
354        let symbol = &mut self.symbols[index.0];
355
356        Ok(Some(symbol))
357    }
358
359    pub fn get_function_containing(&self, addr: u32) -> Option<(SymFunction, &Symbol)> {
360        self.symbols_by_address
361            .range(0..=addr)
362            .rev()
363            .filter_map(|(_, indices)| {
364                let index = indices.first()?;
365                let symbol = &self.symbols[index.0];
366                if let SymbolKind::Function(func) = symbol.kind {
367                    Some((func, symbol))
368                } else {
369                    None
370                }
371            })
372            .take_while(|(func, sym)| func.contains(sym, addr))
373            .next()
374    }
375
376    pub fn functions(&self) -> impl Iterator<Item = (SymFunction, &'_ Symbol)> {
377        FunctionSymbolIterator {
378            symbols_by_address: self.symbols_by_address.values(),
379            indices: [].iter(),
380            symbols: &self.symbols,
381        }
382    }
383
384    pub fn clone_functions(&self) -> Vec<(SymFunction, Symbol)> {
385        self.functions().map(|(function, symbol)| (function, symbol.clone())).collect()
386    }
387
388    pub fn data_symbols(&self) -> impl Iterator<Item = (SymData, &'_ Symbol)> {
389        self.symbols.iter().filter_map(|symbol| {
390            if let SymbolKind::Data(sym_data) = symbol.kind {
391                Some((sym_data, symbol))
392            } else {
393                None
394            }
395        })
396    }
397
398    pub fn bss_symbols(&self) -> impl Iterator<Item = (SymBss, &'_ Symbol)> {
399        self.symbols.iter().filter_map(|symbol| {
400            if let SymbolKind::Bss(sym_bss) = symbol.kind {
401                Some((sym_bss, symbol))
402            } else {
403                None
404            }
405        })
406    }
407
408    pub fn label_name(addr: u32) -> String {
409        format!(".L_{addr:08x}")
410    }
411
412    pub fn add_label(&mut self, addr: u32, thumb: bool) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
413        let name = Self::label_name(addr);
414        self.add_if_new_address(Symbol::new_label(name, addr, thumb))
415    }
416
417    /// See [SymLabel::external].
418    pub fn add_external_label(&mut self, addr: u32, thumb: bool) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
419        let name = Self::label_name(addr);
420        self.add_if_new_address(Symbol::new_external_label(name, addr, thumb))
421    }
422
423    pub fn get_label(&self, addr: u32) -> Result<Option<&Symbol>, SymbolMapError> {
424        Ok(self.by_address(addr)?.and_then(|(_, s)| (matches!(s.kind, SymbolKind::Label { .. })).then_some(s)))
425    }
426
427    pub fn add_pool_constant(&mut self, addr: u32) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
428        let name = Self::label_name(addr);
429        self.add_if_new_address(Symbol::new_pool_constant(name, addr))
430    }
431
432    pub fn get_pool_constant(&self, addr: u32) -> Result<Option<&Symbol>, SymbolMapError> {
433        Ok(self.by_address(addr)?.and_then(|(_, s)| (s.kind == SymbolKind::PoolConstant).then_some(s)))
434    }
435
436    pub fn get_jump_table(&self, addr: u32) -> Result<Option<(SymJumpTable, &Symbol)>, SymbolMapError> {
437        Ok(self.by_address(addr)?.and_then(|(_, s)| match s.kind {
438            SymbolKind::JumpTable(jump_table) => Some((jump_table, s)),
439            _ => None,
440        }))
441    }
442
443    fn make_unambiguous(&mut self, addr: u32) -> Result<(), SymbolMapError> {
444        if let Some(index) = self
445            .by_address(addr)?
446            .filter(|(_, symbol)| matches!(symbol.kind, SymbolKind::Data(_) | SymbolKind::Bss(_)))
447            .map(|(index, _)| index)
448        {
449            self.symbols[index.0].ambiguous = false;
450        }
451        Ok(())
452    }
453
454    pub fn add_function(&mut self, function: &Function) -> (SymbolIndex, &Symbol) {
455        self.add(Symbol::from_function(function))
456    }
457
458    pub fn add_unknown_function(&mut self, name: String, addr: u32, thumb: bool) -> (SymbolIndex, &Symbol) {
459        self.add(Symbol::new_unknown_function(name, addr & !1, thumb))
460    }
461
462    pub fn add_jump_table(&mut self, table: &JumpTable) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
463        let name = Self::label_name(table.address);
464        self.add_if_new_address(Symbol::new_jump_table(name, table.address, table.size, table.code))
465    }
466
467    pub fn add_data(
468        &mut self,
469        name: Option<String>,
470        addr: u32,
471        data: SymData,
472    ) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
473        let name = name.unwrap_or_else(|| Self::label_name(addr));
474        self.make_unambiguous(addr)?;
475        self.add_if_new_address(Symbol::new_data(name, addr, data, false))
476    }
477
478    pub fn add_ambiguous_data(
479        &mut self,
480        name: Option<String>,
481        addr: u32,
482        data: SymData,
483    ) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
484        let name = name.unwrap_or_else(|| Self::label_name(addr));
485        self.add_if_new_address(Symbol::new_data(name, addr, data, true))
486    }
487
488    pub fn add_skip_data(
489        &mut self,
490        name: Option<String>,
491        addr: u32,
492        data: SymData,
493    ) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
494        let name = name.unwrap_or_else(|| Self::label_name(addr));
495        self.add_if_new_address(Symbol::new_skip_data(name, addr, data, true))
496    }
497
498    pub fn get_data(&self, addr: u32) -> Result<Option<(SymData, &Symbol)>, SymbolMapError> {
499        Ok(self.by_address(addr)?.and_then(|(_, s)| match s.kind {
500            SymbolKind::Data(data) => Some((data, s)),
501            _ => None,
502        }))
503    }
504
505    pub fn add_bss(
506        &mut self,
507        name: Option<String>,
508        addr: u32,
509        data: SymBss,
510    ) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
511        let name = name.unwrap_or_else(|| Self::label_name(addr));
512        self.make_unambiguous(addr)?;
513        self.add_if_new_address(Symbol::new_bss(name, addr, data, false))
514    }
515
516    pub fn add_ambiguous_bss(
517        &mut self,
518        name: Option<String>,
519        addr: u32,
520        data: SymBss,
521    ) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
522        let name = name.unwrap_or_else(|| Self::label_name(addr));
523        self.add_if_new_address(Symbol::new_bss(name, addr, data, true))
524    }
525
526    /// Renames a symbol at the given address to the new name.
527    ///
528    /// Returns true if the symbol was renamed, or false if it was already named the same.
529    pub fn rename_by_address(&mut self, address: u32, new_name: &str) -> Result<bool, SymbolMapError> {
530        let symbol_indices =
531            self.symbols_by_address.get(&address).ok_or_else(|| NoSymbolToRenameSnafu { address, new_name }.build())?;
532        ensure!(symbol_indices.len() == 1, RenameMultipleSnafu { address, new_name });
533
534        let symbol_index = symbol_indices[0];
535        let name = &self.symbols[symbol_index.0].name;
536        if name == new_name {
537            return Ok(false);
538        }
539
540        match self.symbols_by_name.entry(name.clone()) {
541            hash_map::Entry::Occupied(mut entry) => {
542                let symbol_indices = entry.get_mut();
543                if symbol_indices.len() == 1 {
544                    entry.remove();
545                } else {
546                    // Remove the to-be-renamed symbol's index from the list of indices of symbols with the same name
547                    let pos = symbol_indices.iter().position(|&i| i == symbol_index).unwrap();
548                    symbol_indices.remove(pos);
549                }
550            }
551            hash_map::Entry::Vacant(_) => {
552                panic!("No symbol name entry found for '{name}' when trying to rename to '{new_name}'");
553            }
554        }
555
556        match self.symbols_by_name.entry(new_name.to_string()) {
557            hash_map::Entry::Occupied(mut entry) => {
558                entry.get_mut().push(symbol_index);
559            }
560            hash_map::Entry::Vacant(entry) => {
561                entry.insert(vec![symbol_index]);
562            }
563        }
564
565        self.symbols[symbol_index.0].name = new_name.to_string();
566
567        Ok(true)
568    }
569}
570
571pub struct SymbolIterator<'a> {
572    symbols_by_address: btree_map::Range<'a, u32, Vec<SymbolIndex>>,
573    indices: slice::Iter<'a, SymbolIndex>,
574    symbols: &'a [Symbol],
575}
576
577impl<'a> Iterator for SymbolIterator<'a> {
578    type Item = &'a Symbol;
579
580    fn next(&mut self) -> Option<Self::Item> {
581        if let Some(&index) = self.indices.next() {
582            Some(&self.symbols[index.0])
583        } else if let Some((_, indices)) = self.symbols_by_address.next() {
584            self.indices = indices.iter();
585            self.next()
586        } else {
587            None
588        }
589    }
590}
591
592impl<'a> DoubleEndedIterator for SymbolIterator<'a> {
593    fn next_back(&mut self) -> Option<Self::Item> {
594        if let Some(&index) = self.indices.next_back() {
595            Some(&self.symbols[index.0])
596        } else if let Some((_, indices)) = self.symbols_by_address.next_back() {
597            self.indices = indices.iter();
598            self.next_back()
599        } else {
600            None
601        }
602    }
603}
604
605pub struct FunctionSymbolIterator<'a, I: Iterator<Item = &'a Vec<SymbolIndex>>> {
606    symbols_by_address: I, //btree_map::Values<'a, u32, Vec<SymbolIndex>>,
607    indices: slice::Iter<'a, SymbolIndex>,
608    symbols: &'a [Symbol],
609}
610
611impl<'a, I: Iterator<Item = &'a Vec<SymbolIndex>>> FunctionSymbolIterator<'a, I> {
612    fn next_function(&mut self) -> Option<(SymFunction, &'a Symbol)> {
613        for &index in self.indices.by_ref() {
614            let symbol = &self.symbols[index.0];
615            if let SymbolKind::Function(function) = symbol.kind {
616                return Some((function, symbol));
617            }
618        }
619        None
620    }
621}
622
623impl<'a, I: Iterator<Item = &'a Vec<SymbolIndex>>> Iterator for FunctionSymbolIterator<'a, I> {
624    type Item = (SymFunction, &'a Symbol);
625
626    fn next(&mut self) -> Option<Self::Item> {
627        if let Some(function) = self.next_function() {
628            return Some(function);
629        }
630        while let Some(indices) = self.symbols_by_address.next() {
631            self.indices = indices.iter();
632            if let Some(function) = self.next_function() {
633                return Some(function);
634            }
635        }
636        None
637    }
638}
639
640#[derive(Clone)]
641pub struct Symbol {
642    pub name: String,
643    pub kind: SymbolKind,
644    pub addr: u32,
645    /// If true, this symbol is involved in an ambiguous external reference to one of many overlays
646    pub ambiguous: bool,
647    /// If true, this symbol is local to its translation unit and will not cause duplicate symbol definitions in the linker
648    pub local: bool,
649    /// If true, this symbol will not be delinked or written to symbols.txt
650    /// Used for symbols that are found during code analysis but whose size are accounted for by their function
651    pub skip: bool,
652}
653
654#[derive(Debug, Snafu)]
655pub enum SymbolParseError {
656    #[snafu(transparent)]
657    SymbolKindParse { source: SymbolKindParseError },
658    #[snafu(display("{context}: failed to parse address '{value}': {error}\n{backtrace}"))]
659    ParseAddress { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
660    #[snafu(display("{context}: expected symbol attribute 'kind' or 'addr' but got '{key}':\n{backtrace}"))]
661    UnknownAttribute { context: ParseContext, key: String, backtrace: Backtrace },
662    #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
663    MissingAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
664}
665
666impl Symbol {
667    fn parse(line: &str, context: &ParseContext) -> Result<Option<Self>, SymbolParseError> {
668        let mut words = line.split_whitespace();
669        let Some(name) = words.next() else { return Ok(None) };
670
671        let mut kind = None;
672        let mut addr = None;
673        let mut ambiguous = false;
674        let mut local = false;
675        for (key, value) in iter_attributes(words) {
676            match key {
677                "kind" => kind = Some(SymbolKind::parse(value, context)?),
678                "addr" => addr = Some(parse_u32(value).map_err(|error| ParseAddressSnafu { context, value, error }.build())?),
679                "ambiguous" => ambiguous = true,
680                "local" => local = true,
681                _ => return UnknownAttributeSnafu { context, key }.fail(),
682            }
683        }
684
685        let name = name.to_string();
686        let kind = kind.ok_or_else(|| MissingAttributeSnafu { context, attribute: "kind" }.build())?;
687        let addr = addr.ok_or_else(|| MissingAttributeSnafu { context, attribute: "addr" }.build())?;
688
689        Ok(Some(Symbol { name, kind, addr, ambiguous, local, skip: false }))
690    }
691
692    fn should_write(&self) -> bool {
693        !self.skip && self.kind.should_write()
694    }
695
696    pub fn from_function(function: &Function) -> Self {
697        Self {
698            name: function.name().to_string(),
699            kind: SymbolKind::Function(SymFunction {
700                mode: InstructionMode::from_thumb(function.is_thumb()),
701                size: function.size(),
702                unknown: false,
703            }),
704            addr: function.first_instruction_address() & !1,
705            ambiguous: false,
706            local: false,
707            skip: false,
708        }
709    }
710
711    pub fn new_unknown_function(name: String, addr: u32, thumb: bool) -> Self {
712        Self {
713            name,
714            kind: SymbolKind::Function(SymFunction { mode: InstructionMode::from_thumb(thumb), size: 0, unknown: true }),
715            addr,
716            ambiguous: false,
717            local: false,
718            skip: false,
719        }
720    }
721
722    pub fn new_label(name: String, addr: u32, thumb: bool) -> Self {
723        Self {
724            name,
725            kind: SymbolKind::Label(SymLabel { external: false, mode: InstructionMode::from_thumb(thumb) }),
726            addr,
727            ambiguous: false,
728            local: true,
729            skip: false,
730        }
731    }
732
733    pub fn new_external_label(name: String, addr: u32, thumb: bool) -> Self {
734        Self {
735            name,
736            kind: SymbolKind::Label(SymLabel { external: true, mode: InstructionMode::from_thumb(thumb) }),
737            addr,
738            ambiguous: false,
739            local: false,
740            skip: false,
741        }
742    }
743
744    pub fn new_pool_constant(name: String, addr: u32) -> Self {
745        Self { name, kind: SymbolKind::PoolConstant, addr, ambiguous: false, local: true, skip: false }
746    }
747
748    pub fn new_jump_table(name: String, addr: u32, size: u32, code: bool) -> Self {
749        Self {
750            name,
751            kind: SymbolKind::JumpTable(SymJumpTable { size, code }),
752            addr,
753            ambiguous: false,
754            local: true,
755            skip: false,
756        }
757    }
758
759    pub fn new_data(name: String, addr: u32, data: SymData, ambiguous: bool) -> Symbol {
760        Self { name, kind: SymbolKind::Data(data), addr, ambiguous, local: false, skip: false }
761    }
762
763    pub fn new_skip_data(name: String, addr: u32, data: SymData, ambiguous: bool) -> Symbol {
764        Self { name, kind: SymbolKind::Data(data), addr, ambiguous, local: false, skip: true }
765    }
766
767    pub fn new_bss(name: String, addr: u32, data: SymBss, ambiguous: bool) -> Symbol {
768        Self { name, kind: SymbolKind::Bss(data), addr, ambiguous, local: false, skip: false }
769    }
770
771    pub fn size(&self, max_address: u32) -> u32 {
772        self.kind.size(max_address - self.addr)
773    }
774
775    pub fn is_external(&self) -> bool {
776        match self.kind {
777            SymbolKind::Label(SymLabel { external, .. }) => external,
778            SymbolKind::PoolConstant => false,
779            SymbolKind::JumpTable(_) => false,
780            _ => true,
781        }
782    }
783}
784
785impl Display for Symbol {
786    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
787        write!(f, "{} kind:{} addr:{:#010x}", self.name, self.kind, self.addr)?;
788        if self.local {
789            write!(f, " local")?;
790        }
791        if self.ambiguous {
792            write!(f, " ambiguous")?;
793        }
794        Ok(())
795    }
796}
797
798#[derive(Clone, Copy, PartialEq, Eq, Debug)]
799pub enum SymbolKind {
800    Undefined,
801    Function(SymFunction),
802    Label(SymLabel),
803    PoolConstant,
804    JumpTable(SymJumpTable),
805    Data(SymData),
806    Bss(SymBss),
807}
808
809#[derive(Debug, Snafu)]
810pub enum SymbolKindParseError {
811    #[snafu(transparent)]
812    SymFunctionParse { source: SymFunctionParseError },
813    #[snafu(transparent)]
814    SymDataParse { source: SymDataParseError },
815    #[snafu(transparent)]
816    SymBssParse { source: SymBssParseError },
817    #[snafu(transparent)]
818    SymLabelParse { source: SymLabelParseError },
819    #[snafu(display("{context}: unknown symbol kind '{kind}', must be one of: function, data, bss, label:\n{backtrace}"))]
820    UnknownKind { context: ParseContext, kind: String, backtrace: Backtrace },
821}
822
823impl SymbolKind {
824    fn parse(text: &str, context: &ParseContext) -> Result<Self, SymbolKindParseError> {
825        let (kind, options) = text.split_once('(').unwrap_or((text, ""));
826        let options = options.strip_suffix(')').unwrap_or(options);
827
828        match kind {
829            "function" => Ok(Self::Function(SymFunction::parse(options, context)?)),
830            "data" => Ok(Self::Data(SymData::parse(options, context)?)),
831            "bss" => Ok(Self::Bss(SymBss::parse(options, context)?)),
832            "label" => Ok(Self::Label(SymLabel::parse(options, context)?)),
833            _ => UnknownKindSnafu { context, kind }.fail(),
834        }
835    }
836
837    fn should_write(&self) -> bool {
838        match self {
839            SymbolKind::Undefined => false,
840            SymbolKind::Function(_) => true,
841            SymbolKind::Label(label) => label.external,
842            SymbolKind::PoolConstant => false,
843            SymbolKind::JumpTable(_) => false,
844            SymbolKind::Data(_) => true,
845            SymbolKind::Bss(_) => true,
846        }
847    }
848
849    pub fn size(&self, max_size: u32) -> u32 {
850        match self {
851            SymbolKind::Undefined => 0,
852            SymbolKind::Function(function) => function.size,
853            SymbolKind::Label(_) => 0,
854            SymbolKind::PoolConstant => 0, // actually 4, but pool constants are just labels
855            SymbolKind::JumpTable(_) => 0,
856            SymbolKind::Data(data) => data.size().unwrap_or(max_size),
857            SymbolKind::Bss(bss) => bss.size.unwrap_or(max_size),
858        }
859    }
860}
861
862impl Display for SymbolKind {
863    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
864        match self {
865            SymbolKind::Undefined => {}
866            SymbolKind::Function(function) => write!(f, "function({function})")?,
867            SymbolKind::Data(data) => write!(f, "data({data})")?,
868            SymbolKind::Bss(bss) => write!(f, "bss{bss}")?,
869            SymbolKind::Label(label) => write!(f, "label({label})")?,
870            SymbolKind::PoolConstant => {}
871            SymbolKind::JumpTable(_) => {}
872        }
873        Ok(())
874    }
875}
876
877#[derive(Clone, Copy, PartialEq, Eq, Debug)]
878pub struct SymFunction {
879    pub mode: InstructionMode,
880    pub size: u32,
881    /// Is `true` for functions that were not found during function analysis, but are being called from somewhere. This can
882    /// happen if the function is encrypted.
883    pub unknown: bool,
884}
885
886#[derive(Debug, Snafu)]
887pub enum SymFunctionParseError {
888    #[snafu(display("{context}: failed to parse size '{value}': {error}\n{backtrace}"))]
889    ParseFunctionSize { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
890    #[snafu(display(
891        "{context}: unknown function attribute '{key}', must be one of: size, unknown, arm, thumb:\n{backtrace}"
892    ))]
893    UnknownFunctionAttribute { context: ParseContext, key: String, backtrace: Backtrace },
894    #[snafu(transparent)]
895    InstructionModeParse { source: InstructionModeParseError },
896    #[snafu(display("{context}: function must have an instruction mode: arm or thumb"))]
897    MissingInstructionMode { context: ParseContext, backtrace: Backtrace },
898    #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
899    MissingFunctionAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
900}
901
902impl SymFunction {
903    fn parse(options: &str, context: &ParseContext) -> Result<Self, SymFunctionParseError> {
904        let mut size = None;
905        let mut mode = None;
906        let mut unknown = false;
907        for option in options.split(',') {
908            if let Some((key, value)) = option.split_once('=') {
909                match key {
910                    "size" => {
911                        size =
912                            Some(parse_u32(value).map_err(|error| ParseFunctionSizeSnafu { context, value, error }.build())?)
913                    }
914                    _ => return UnknownFunctionAttributeSnafu { context, key }.fail(),
915                }
916            } else {
917                match option {
918                    "unknown" => unknown = true,
919                    _ => mode = Some(InstructionMode::parse(option, context)?),
920                }
921            }
922        }
923
924        Ok(Self {
925            mode: mode.ok_or_else(|| MissingInstructionModeSnafu { context }.build())?,
926            size: size.ok_or_else(|| MissingFunctionAttributeSnafu { context, attribute: "size" }.build())?,
927            unknown,
928        })
929    }
930
931    fn contains(&self, sym: &Symbol, addr: u32) -> bool {
932        if !self.unknown {
933            let start = sym.addr;
934            let end = start + self.size;
935            addr >= start && addr < end
936        } else {
937            // Unknown functions have no size
938            sym.addr == addr
939        }
940    }
941}
942
943impl Display for SymFunction {
944    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
945        write!(f, "{},size={:#x}", self.mode, self.size)?;
946        if self.unknown {
947            write!(f, ",unknown")?;
948        }
949        Ok(())
950    }
951}
952
953#[derive(Clone, Copy, PartialEq, Eq, Debug)]
954pub struct SymLabel {
955    /// If true, the label is not used by the function itself, but accessed externally. Such labels are only discovered
956    /// during relocation analysis, which is not performed by the dis/delink subcommands. External label symbols are
957    /// therefore included in symbols.txt, hence this boolean.
958    pub external: bool,
959    pub mode: InstructionMode,
960}
961
962#[derive(Debug, Snafu)]
963pub enum SymLabelParseError {
964    #[snafu(transparent)]
965    InstructionModeParse { source: InstructionModeParseError },
966}
967
968impl SymLabel {
969    fn parse(options: &str, context: &ParseContext) -> Result<Self, SymLabelParseError> {
970        Ok(Self { external: true, mode: InstructionMode::parse(options, context)? })
971    }
972}
973
974impl Display for SymLabel {
975    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
976        write!(f, "{}", self.mode)
977    }
978}
979
980#[derive(Clone, Copy, PartialEq, Eq, Debug)]
981pub enum InstructionMode {
982    Arm,
983    Thumb,
984}
985
986#[derive(Debug, Snafu)]
987pub enum InstructionModeParseError {
988    #[snafu(display("{context}: expected instruction mode 'arm' or 'thumb' but got '{value}':\n{backtrace}"))]
989    UnknownInstructionMode { context: ParseContext, value: String, backtrace: Backtrace },
990}
991
992impl InstructionMode {
993    fn parse(value: &str, context: &ParseContext) -> Result<Self, InstructionModeParseError> {
994        match value {
995            "arm" => Ok(Self::Arm),
996            "thumb" => Ok(Self::Thumb),
997            _ => UnknownInstructionModeSnafu { context, value }.fail(),
998        }
999    }
1000
1001    pub fn from_thumb(thumb: bool) -> Self {
1002        if thumb { Self::Thumb } else { Self::Arm }
1003    }
1004
1005    pub fn into_thumb(self) -> Option<bool> {
1006        match self {
1007            Self::Arm => Some(false),
1008            Self::Thumb => Some(true),
1009        }
1010    }
1011}
1012
1013impl Display for InstructionMode {
1014    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1015        match self {
1016            Self::Arm => write!(f, "arm"),
1017            Self::Thumb => write!(f, "thumb"),
1018        }
1019    }
1020}
1021
1022#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1023pub struct SymJumpTable {
1024    pub size: u32,
1025    pub code: bool,
1026}
1027
1028#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1029pub enum SymData {
1030    Any,
1031    Byte { count: Option<u32> },
1032    Short { count: Option<u32> },
1033    Word { count: Option<u32> },
1034}
1035
1036#[derive(Debug, Snafu)]
1037pub enum SymDataParseError {
1038    #[snafu(display("{context}: expected data kind 'any', 'byte', 'short' or 'word' but got nothing:\n{backtrace}"))]
1039    EmptyData { context: ParseContext, backtrace: Backtrace },
1040    #[snafu(display("{context}: failed to parse count '{value}': {error}\n{backtrace}"))]
1041    ParseCount { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
1042    #[snafu(display("{context}: unexpected characters after ']':\n{backtrace}"))]
1043    CharacterAfterArray { context: ParseContext, backtrace: Backtrace },
1044    #[snafu(display("{context}: data type 'any' cannot be an array:\n{backtrace}"))]
1045    ArrayOfAny { context: ParseContext, backtrace: Backtrace },
1046    #[snafu(display("{context}: expected data kind 'any', 'byte', 'short' or 'word' but got '{kind}':\n{backtrace}"))]
1047    UnknownDataKind { context: ParseContext, kind: String, backtrace: Backtrace },
1048}
1049
1050impl SymData {
1051    fn parse(kind: &str, context: &ParseContext) -> Result<Self, SymDataParseError> {
1052        if kind.is_empty() {
1053            return EmptyDataSnafu { context }.fail();
1054        }
1055
1056        let (kind, rest) = kind.split_once('[').unwrap_or((kind, ""));
1057        let (count, rest) = rest
1058            .split_once(']')
1059            .map(|(count, rest)| {
1060                let count = if count.is_empty() {
1061                    Ok(None)
1062                } else {
1063                    parse_u32(count).map(Some).map_err(|error| ParseCountSnafu { context, value: count, error }.build())
1064                };
1065                (count, rest)
1066            })
1067            .unwrap_or((Ok(Some(1)), rest));
1068        let count = count?;
1069
1070        if !rest.is_empty() {
1071            return CharacterAfterArraySnafu { context }.fail();
1072        }
1073
1074        match kind {
1075            "any" => {
1076                if count != Some(1) {
1077                    ArrayOfAnySnafu { context }.fail()
1078                } else {
1079                    Ok(Self::Any)
1080                }
1081            }
1082            "short" => Ok(Self::Short { count }),
1083            "byte" => Ok(Self::Byte { count }),
1084            "word" => Ok(Self::Word { count }),
1085            kind => UnknownDataKindSnafu { context, kind }.fail(),
1086        }
1087    }
1088
1089    pub fn count(self) -> Option<u32> {
1090        match self {
1091            Self::Any => None,
1092            Self::Byte { count } => count,
1093            Self::Short { count } => count,
1094            Self::Word { count } => count,
1095        }
1096    }
1097
1098    pub fn element_size(self) -> u32 {
1099        match self {
1100            Self::Any => 1,
1101            Self::Byte { .. } => 1,
1102            Self::Short { .. } => 2,
1103            Self::Word { .. } => 4,
1104        }
1105    }
1106
1107    pub fn size(&self) -> Option<u32> {
1108        self.count().map(|count| self.element_size() * count)
1109    }
1110}
1111
1112impl Display for SymData {
1113    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1114        match self {
1115            Self::Any => write!(f, "any"),
1116            Self::Byte { count: Some(1) } => write!(f, "byte"),
1117            Self::Short { count: Some(1) } => write!(f, "short"),
1118            Self::Word { count: Some(1) } => write!(f, "word"),
1119            Self::Byte { count: Some(count) } => write!(f, "byte[{count}]"),
1120            Self::Short { count: Some(count) } => write!(f, "short[{count}]"),
1121            Self::Word { count: Some(count) } => write!(f, "word[{count}]"),
1122            Self::Byte { count: None } => write!(f, "byte[]"),
1123            Self::Short { count: None } => write!(f, "short[]"),
1124            Self::Word { count: None } => write!(f, "word[]"),
1125        }
1126    }
1127}
1128
1129#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1130pub struct SymBss {
1131    pub size: Option<u32>,
1132}
1133
1134#[derive(Debug, Snafu)]
1135pub enum SymBssParseError {
1136    #[snafu(display("{context}: failed to parse size '{value}': {error}\n{backtrace}"))]
1137    ParseBssSize { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
1138    #[snafu(display("{context}: unknown attribute '{key}', must be one of: size:\n{backtrace}'"))]
1139    UnknownBssAttribute { context: ParseContext, key: String, backtrace: Backtrace },
1140}
1141
1142impl SymBss {
1143    fn parse(options: &str, context: &ParseContext) -> Result<Self, SymBssParseError> {
1144        let mut size = None;
1145        if !options.trim().is_empty() {
1146            for option in options.split(',') {
1147                if let Some((key, value)) = option.split_once('=') {
1148                    match key {
1149                        "size" => {
1150                            size = Some(parse_u32(value).map_err(|error| ParseBssSizeSnafu { context, value, error }.build())?)
1151                        }
1152                        _ => return UnknownBssAttributeSnafu { context, key }.fail(),
1153                    }
1154                } else {
1155                    return UnknownBssAttributeSnafu { context, key: option }.fail();
1156                }
1157            }
1158        }
1159        Ok(Self { size })
1160    }
1161}
1162
1163impl Display for SymBss {
1164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1165        if let Some(size) = self.size {
1166            write!(f, "(size={size:#x})")?;
1167        }
1168        Ok(())
1169    }
1170}