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 get_data(&self, addr: u32) -> Result<Option<(SymData, &Symbol)>, SymbolMapError> {
489        Ok(self.by_address(addr)?.and_then(|(_, s)| match s.kind {
490            SymbolKind::Data(data) => Some((data, s)),
491            _ => None,
492        }))
493    }
494
495    pub fn add_bss(
496        &mut self,
497        name: Option<String>,
498        addr: u32,
499        data: SymBss,
500    ) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
501        let name = name.unwrap_or_else(|| Self::label_name(addr));
502        self.make_unambiguous(addr)?;
503        self.add_if_new_address(Symbol::new_bss(name, addr, data, false))
504    }
505
506    pub fn add_ambiguous_bss(
507        &mut self,
508        name: Option<String>,
509        addr: u32,
510        data: SymBss,
511    ) -> Result<(SymbolIndex, &Symbol), SymbolMapError> {
512        let name = name.unwrap_or_else(|| Self::label_name(addr));
513        self.add_if_new_address(Symbol::new_bss(name, addr, data, true))
514    }
515
516    /// Renames a symbol at the given address to the new name.
517    ///
518    /// Returns true if the symbol was renamed, or false if it was already named the same.
519    pub fn rename_by_address(&mut self, address: u32, new_name: &str) -> Result<bool, SymbolMapError> {
520        let symbol_indices =
521            self.symbols_by_address.get(&address).ok_or_else(|| NoSymbolToRenameSnafu { address, new_name }.build())?;
522        ensure!(symbol_indices.len() == 1, RenameMultipleSnafu { address, new_name });
523
524        let symbol_index = symbol_indices[0];
525        let name = &self.symbols[symbol_index.0].name;
526        if name == new_name {
527            return Ok(false);
528        }
529
530        match self.symbols_by_name.entry(name.clone()) {
531            hash_map::Entry::Occupied(mut entry) => {
532                let symbol_indices = entry.get_mut();
533                if symbol_indices.len() == 1 {
534                    entry.remove();
535                } else {
536                    // Remove the to-be-renamed symbol's index from the list of indices of symbols with the same name
537                    let pos = symbol_indices.iter().position(|&i| i == symbol_index).unwrap();
538                    symbol_indices.remove(pos);
539                }
540            }
541            hash_map::Entry::Vacant(_) => {
542                panic!("No symbol name entry found for '{name}' when trying to rename to '{new_name}'");
543            }
544        }
545
546        match self.symbols_by_name.entry(new_name.to_string()) {
547            hash_map::Entry::Occupied(mut entry) => {
548                entry.get_mut().push(symbol_index);
549            }
550            hash_map::Entry::Vacant(entry) => {
551                entry.insert(vec![symbol_index]);
552            }
553        }
554
555        self.symbols[symbol_index.0].name = new_name.to_string();
556
557        Ok(true)
558    }
559}
560
561pub struct SymbolIterator<'a> {
562    symbols_by_address: btree_map::Range<'a, u32, Vec<SymbolIndex>>,
563    indices: slice::Iter<'a, SymbolIndex>,
564    symbols: &'a [Symbol],
565}
566
567impl<'a> Iterator for SymbolIterator<'a> {
568    type Item = &'a Symbol;
569
570    fn next(&mut self) -> Option<Self::Item> {
571        if let Some(&index) = self.indices.next() {
572            Some(&self.symbols[index.0])
573        } else if let Some((_, indices)) = self.symbols_by_address.next() {
574            self.indices = indices.iter();
575            self.next()
576        } else {
577            None
578        }
579    }
580}
581
582impl<'a> DoubleEndedIterator for SymbolIterator<'a> {
583    fn next_back(&mut self) -> Option<Self::Item> {
584        if let Some(&index) = self.indices.next_back() {
585            Some(&self.symbols[index.0])
586        } else if let Some((_, indices)) = self.symbols_by_address.next_back() {
587            self.indices = indices.iter();
588            self.next_back()
589        } else {
590            None
591        }
592    }
593}
594
595pub struct FunctionSymbolIterator<'a, I: Iterator<Item = &'a Vec<SymbolIndex>>> {
596    symbols_by_address: I, //btree_map::Values<'a, u32, Vec<SymbolIndex>>,
597    indices: slice::Iter<'a, SymbolIndex>,
598    symbols: &'a [Symbol],
599}
600
601impl<'a, I: Iterator<Item = &'a Vec<SymbolIndex>>> FunctionSymbolIterator<'a, I> {
602    fn next_function(&mut self) -> Option<(SymFunction, &'a Symbol)> {
603        for &index in self.indices.by_ref() {
604            let symbol = &self.symbols[index.0];
605            if let SymbolKind::Function(function) = symbol.kind {
606                return Some((function, symbol));
607            }
608        }
609        None
610    }
611}
612
613impl<'a, I: Iterator<Item = &'a Vec<SymbolIndex>>> Iterator for FunctionSymbolIterator<'a, I> {
614    type Item = (SymFunction, &'a Symbol);
615
616    fn next(&mut self) -> Option<Self::Item> {
617        if let Some(function) = self.next_function() {
618            return Some(function);
619        }
620        while let Some(indices) = self.symbols_by_address.next() {
621            self.indices = indices.iter();
622            if let Some(function) = self.next_function() {
623                return Some(function);
624            }
625        }
626        None
627    }
628}
629
630#[derive(Clone)]
631pub struct Symbol {
632    pub name: String,
633    pub kind: SymbolKind,
634    pub addr: u32,
635    /// If true, this symbol is involved in an ambiguous external reference to one of many overlays
636    pub ambiguous: bool,
637    /// If true, this symbol is local to its translation unit and will not cause duplicate symbol definitions in the linker
638    pub local: bool,
639}
640
641#[derive(Debug, Snafu)]
642pub enum SymbolParseError {
643    #[snafu(transparent)]
644    SymbolKindParse { source: SymbolKindParseError },
645    #[snafu(display("{context}: failed to parse address '{value}': {error}\n{backtrace}"))]
646    ParseAddress { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
647    #[snafu(display("{context}: expected symbol attribute 'kind' or 'addr' but got '{key}':\n{backtrace}"))]
648    UnknownAttribute { context: ParseContext, key: String, backtrace: Backtrace },
649    #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
650    MissingAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
651}
652
653impl Symbol {
654    fn parse(line: &str, context: &ParseContext) -> Result<Option<Self>, SymbolParseError> {
655        let mut words = line.split_whitespace();
656        let Some(name) = words.next() else { return Ok(None) };
657
658        let mut kind = None;
659        let mut addr = None;
660        let mut ambiguous = false;
661        let mut local = false;
662        for (key, value) in iter_attributes(words) {
663            match key {
664                "kind" => kind = Some(SymbolKind::parse(value, context)?),
665                "addr" => addr = Some(parse_u32(value).map_err(|error| ParseAddressSnafu { context, value, error }.build())?),
666                "ambiguous" => ambiguous = true,
667                "local" => local = true,
668                _ => return UnknownAttributeSnafu { context, key }.fail(),
669            }
670        }
671
672        let name = name.to_string();
673        let kind = kind.ok_or_else(|| MissingAttributeSnafu { context, attribute: "kind" }.build())?;
674        let addr = addr.ok_or_else(|| MissingAttributeSnafu { context, attribute: "addr" }.build())?;
675
676        Ok(Some(Symbol { name, kind, addr, ambiguous, local }))
677    }
678
679    fn should_write(&self) -> bool {
680        self.kind.should_write()
681    }
682
683    pub fn from_function(function: &Function) -> Self {
684        Self {
685            name: function.name().to_string(),
686            kind: SymbolKind::Function(SymFunction {
687                mode: InstructionMode::from_thumb(function.is_thumb()),
688                size: function.size(),
689                unknown: false,
690            }),
691            addr: function.first_instruction_address() & !1,
692            ambiguous: false,
693            local: false,
694        }
695    }
696
697    pub fn new_unknown_function(name: String, addr: u32, thumb: bool) -> Self {
698        Self {
699            name,
700            kind: SymbolKind::Function(SymFunction { mode: InstructionMode::from_thumb(thumb), size: 0, unknown: true }),
701            addr,
702            ambiguous: false,
703            local: false,
704        }
705    }
706
707    pub fn new_label(name: String, addr: u32, thumb: bool) -> Self {
708        Self {
709            name,
710            kind: SymbolKind::Label(SymLabel { external: false, mode: InstructionMode::from_thumb(thumb) }),
711            addr,
712            ambiguous: false,
713            local: true,
714        }
715    }
716
717    pub fn new_external_label(name: String, addr: u32, thumb: bool) -> Self {
718        Self {
719            name,
720            kind: SymbolKind::Label(SymLabel { external: true, mode: InstructionMode::from_thumb(thumb) }),
721            addr,
722            ambiguous: false,
723            local: false,
724        }
725    }
726
727    pub fn new_pool_constant(name: String, addr: u32) -> Self {
728        Self { name, kind: SymbolKind::PoolConstant, addr, ambiguous: false, local: true }
729    }
730
731    pub fn new_jump_table(name: String, addr: u32, size: u32, code: bool) -> Self {
732        Self { name, kind: SymbolKind::JumpTable(SymJumpTable { size, code }), addr, ambiguous: false, local: true }
733    }
734
735    pub fn new_data(name: String, addr: u32, data: SymData, ambiguous: bool) -> Symbol {
736        Self { name, kind: SymbolKind::Data(data), addr, ambiguous, local: false }
737    }
738
739    pub fn new_bss(name: String, addr: u32, data: SymBss, ambiguous: bool) -> Symbol {
740        Self { name, kind: SymbolKind::Bss(data), addr, ambiguous, local: false }
741    }
742
743    pub fn size(&self, max_address: u32) -> u32 {
744        self.kind.size(max_address - self.addr)
745    }
746
747    pub fn is_external(&self) -> bool {
748        match self.kind {
749            SymbolKind::Label(SymLabel { external, .. }) => external,
750            SymbolKind::PoolConstant => false,
751            SymbolKind::JumpTable(_) => false,
752            _ => true,
753        }
754    }
755}
756
757impl Display for Symbol {
758    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
759        write!(f, "{} kind:{} addr:{:#010x}", self.name, self.kind, self.addr)?;
760        if self.local {
761            write!(f, " local")?;
762        }
763        if self.ambiguous {
764            write!(f, " ambiguous")?;
765        }
766        Ok(())
767    }
768}
769
770#[derive(Clone, Copy, PartialEq, Eq, Debug)]
771pub enum SymbolKind {
772    Undefined,
773    Function(SymFunction),
774    Label(SymLabel),
775    PoolConstant,
776    JumpTable(SymJumpTable),
777    Data(SymData),
778    Bss(SymBss),
779}
780
781#[derive(Debug, Snafu)]
782pub enum SymbolKindParseError {
783    #[snafu(transparent)]
784    SymFunctionParse { source: SymFunctionParseError },
785    #[snafu(transparent)]
786    SymDataParse { source: SymDataParseError },
787    #[snafu(transparent)]
788    SymBssParse { source: SymBssParseError },
789    #[snafu(transparent)]
790    SymLabelParse { source: SymLabelParseError },
791    #[snafu(display("{context}: unknown symbol kind '{kind}', must be one of: function, data, bss, label:\n{backtrace}"))]
792    UnknownKind { context: ParseContext, kind: String, backtrace: Backtrace },
793}
794
795impl SymbolKind {
796    fn parse(text: &str, context: &ParseContext) -> Result<Self, SymbolKindParseError> {
797        let (kind, options) = text.split_once('(').unwrap_or((text, ""));
798        let options = options.strip_suffix(')').unwrap_or(options);
799
800        match kind {
801            "function" => Ok(Self::Function(SymFunction::parse(options, context)?)),
802            "data" => Ok(Self::Data(SymData::parse(options, context)?)),
803            "bss" => Ok(Self::Bss(SymBss::parse(options, context)?)),
804            "label" => Ok(Self::Label(SymLabel::parse(options, context)?)),
805            _ => UnknownKindSnafu { context, kind }.fail(),
806        }
807    }
808
809    fn should_write(&self) -> bool {
810        match self {
811            SymbolKind::Undefined => false,
812            SymbolKind::Function(_) => true,
813            SymbolKind::Label(label) => label.external,
814            SymbolKind::PoolConstant => false,
815            SymbolKind::JumpTable(_) => false,
816            SymbolKind::Data(_) => true,
817            SymbolKind::Bss(_) => true,
818        }
819    }
820
821    pub fn size(&self, max_size: u32) -> u32 {
822        match self {
823            SymbolKind::Undefined => 0,
824            SymbolKind::Function(function) => function.size,
825            SymbolKind::Label(_) => 0,
826            SymbolKind::PoolConstant => 0, // actually 4, but pool constants are just labels
827            SymbolKind::JumpTable(_) => 0,
828            SymbolKind::Data(data) => data.size().unwrap_or(max_size),
829            SymbolKind::Bss(bss) => bss.size.unwrap_or(max_size),
830        }
831    }
832}
833
834impl Display for SymbolKind {
835    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
836        match self {
837            SymbolKind::Undefined => {}
838            SymbolKind::Function(function) => write!(f, "function({function})")?,
839            SymbolKind::Data(data) => write!(f, "data({data})")?,
840            SymbolKind::Bss(bss) => write!(f, "bss{bss}")?,
841            SymbolKind::Label(label) => write!(f, "label({label})")?,
842            SymbolKind::PoolConstant => {}
843            SymbolKind::JumpTable(_) => {}
844        }
845        Ok(())
846    }
847}
848
849#[derive(Clone, Copy, PartialEq, Eq, Debug)]
850pub struct SymFunction {
851    pub mode: InstructionMode,
852    pub size: u32,
853    /// Is `true` for functions that were not found during function analysis, but are being called from somewhere. This can
854    /// happen if the function is encrypted.
855    pub unknown: bool,
856}
857
858#[derive(Debug, Snafu)]
859pub enum SymFunctionParseError {
860    #[snafu(display("{context}: failed to parse size '{value}': {error}\n{backtrace}"))]
861    ParseFunctionSize { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
862    #[snafu(display(
863        "{context}: unknown function attribute '{key}', must be one of: size, unknown, arm, thumb:\n{backtrace}"
864    ))]
865    UnknownFunctionAttribute { context: ParseContext, key: String, backtrace: Backtrace },
866    #[snafu(transparent)]
867    InstructionModeParse { source: InstructionModeParseError },
868    #[snafu(display("{context}: function must have an instruction mode: arm or thumb"))]
869    MissingInstructionMode { context: ParseContext, backtrace: Backtrace },
870    #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
871    MissingFunctionAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
872}
873
874impl SymFunction {
875    fn parse(options: &str, context: &ParseContext) -> Result<Self, SymFunctionParseError> {
876        let mut size = None;
877        let mut mode = None;
878        let mut unknown = false;
879        for option in options.split(',') {
880            if let Some((key, value)) = option.split_once('=') {
881                match key {
882                    "size" => {
883                        size =
884                            Some(parse_u32(value).map_err(|error| ParseFunctionSizeSnafu { context, value, error }.build())?)
885                    }
886                    _ => return UnknownFunctionAttributeSnafu { context, key }.fail(),
887                }
888            } else {
889                match option {
890                    "unknown" => unknown = true,
891                    _ => mode = Some(InstructionMode::parse(option, context)?),
892                }
893            }
894        }
895
896        Ok(Self {
897            mode: mode.ok_or_else(|| MissingInstructionModeSnafu { context }.build())?,
898            size: size.ok_or_else(|| MissingFunctionAttributeSnafu { context, attribute: "size" }.build())?,
899            unknown,
900        })
901    }
902
903    fn contains(&self, sym: &Symbol, addr: u32) -> bool {
904        if !self.unknown {
905            let start = sym.addr;
906            let end = start + self.size;
907            addr >= start && addr < end
908        } else {
909            // Unknown functions have no size
910            sym.addr == addr
911        }
912    }
913}
914
915impl Display for SymFunction {
916    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
917        write!(f, "{},size={:#x}", self.mode, self.size)?;
918        if self.unknown {
919            write!(f, ",unknown")?;
920        }
921        Ok(())
922    }
923}
924
925#[derive(Clone, Copy, PartialEq, Eq, Debug)]
926pub struct SymLabel {
927    /// If true, the label is not used by the function itself, but accessed externally. Such labels are only discovered
928    /// during relocation analysis, which is not performed by the dis/delink subcommands. External label symbols are
929    /// therefore included in symbols.txt, hence this boolean.
930    pub external: bool,
931    pub mode: InstructionMode,
932}
933
934#[derive(Debug, Snafu)]
935pub enum SymLabelParseError {
936    #[snafu(transparent)]
937    InstructionModeParse { source: InstructionModeParseError },
938}
939
940impl SymLabel {
941    fn parse(options: &str, context: &ParseContext) -> Result<Self, SymLabelParseError> {
942        Ok(Self { external: true, mode: InstructionMode::parse(options, context)? })
943    }
944}
945
946impl Display for SymLabel {
947    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
948        write!(f, "{}", self.mode)
949    }
950}
951
952#[derive(Clone, Copy, PartialEq, Eq, Debug)]
953pub enum InstructionMode {
954    Arm,
955    Thumb,
956}
957
958#[derive(Debug, Snafu)]
959pub enum InstructionModeParseError {
960    #[snafu(display("{context}: expected instruction mode 'arm' or 'thumb' but got '{value}':\n{backtrace}"))]
961    UnknownInstructionMode { context: ParseContext, value: String, backtrace: Backtrace },
962}
963
964impl InstructionMode {
965    fn parse(value: &str, context: &ParseContext) -> Result<Self, InstructionModeParseError> {
966        match value {
967            "arm" => Ok(Self::Arm),
968            "thumb" => Ok(Self::Thumb),
969            _ => UnknownInstructionModeSnafu { context, value }.fail(),
970        }
971    }
972
973    pub fn from_thumb(thumb: bool) -> Self {
974        if thumb { Self::Thumb } else { Self::Arm }
975    }
976
977    pub fn into_thumb(self) -> Option<bool> {
978        match self {
979            Self::Arm => Some(false),
980            Self::Thumb => Some(true),
981        }
982    }
983}
984
985impl Display for InstructionMode {
986    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
987        match self {
988            Self::Arm => write!(f, "arm"),
989            Self::Thumb => write!(f, "thumb"),
990        }
991    }
992}
993
994#[derive(Clone, Copy, PartialEq, Eq, Debug)]
995pub struct SymJumpTable {
996    pub size: u32,
997    pub code: bool,
998}
999
1000#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1001pub enum SymData {
1002    Any,
1003    Byte { count: Option<u32> },
1004    Short { count: Option<u32> },
1005    Word { count: Option<u32> },
1006}
1007
1008#[derive(Debug, Snafu)]
1009pub enum SymDataParseError {
1010    #[snafu(display("{context}: expected data kind 'any', 'byte', 'short' or 'word' but got nothing:\n{backtrace}"))]
1011    EmptyData { context: ParseContext, backtrace: Backtrace },
1012    #[snafu(display("{context}: failed to parse count '{value}': {error}\n{backtrace}"))]
1013    ParseCount { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
1014    #[snafu(display("{context}: unexpected characters after ']':\n{backtrace}"))]
1015    CharacterAfterArray { context: ParseContext, backtrace: Backtrace },
1016    #[snafu(display("{context}: data type 'any' cannot be an array:\n{backtrace}"))]
1017    ArrayOfAny { context: ParseContext, backtrace: Backtrace },
1018    #[snafu(display("{context}: expected data kind 'any', 'byte', 'short' or 'word' but got '{kind}':\n{backtrace}"))]
1019    UnknownDataKind { context: ParseContext, kind: String, backtrace: Backtrace },
1020}
1021
1022impl SymData {
1023    fn parse(kind: &str, context: &ParseContext) -> Result<Self, SymDataParseError> {
1024        if kind.is_empty() {
1025            return EmptyDataSnafu { context }.fail();
1026        }
1027
1028        let (kind, rest) = kind.split_once('[').unwrap_or((kind, ""));
1029        let (count, rest) = rest
1030            .split_once(']')
1031            .map(|(count, rest)| {
1032                let count = if count.is_empty() {
1033                    Ok(None)
1034                } else {
1035                    parse_u32(count).map(Some).map_err(|error| ParseCountSnafu { context, value: count, error }.build())
1036                };
1037                (count, rest)
1038            })
1039            .unwrap_or((Ok(Some(1)), rest));
1040        let count = count?;
1041
1042        if !rest.is_empty() {
1043            return CharacterAfterArraySnafu { context }.fail();
1044        }
1045
1046        match kind {
1047            "any" => {
1048                if count != Some(1) {
1049                    ArrayOfAnySnafu { context }.fail()
1050                } else {
1051                    Ok(Self::Any)
1052                }
1053            }
1054            "short" => Ok(Self::Short { count }),
1055            "byte" => Ok(Self::Byte { count }),
1056            "word" => Ok(Self::Word { count }),
1057            kind => UnknownDataKindSnafu { context, kind }.fail(),
1058        }
1059    }
1060
1061    pub fn count(self) -> Option<u32> {
1062        match self {
1063            Self::Any => None,
1064            Self::Byte { count } => count,
1065            Self::Short { count } => count,
1066            Self::Word { count } => count,
1067        }
1068    }
1069
1070    pub fn element_size(self) -> u32 {
1071        match self {
1072            Self::Any => 1,
1073            Self::Byte { .. } => 1,
1074            Self::Short { .. } => 2,
1075            Self::Word { .. } => 4,
1076        }
1077    }
1078
1079    pub fn size(&self) -> Option<u32> {
1080        self.count().map(|count| self.element_size() * count)
1081    }
1082}
1083
1084impl Display for SymData {
1085    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1086        match self {
1087            Self::Any => write!(f, "any"),
1088            Self::Byte { count: Some(1) } => write!(f, "byte"),
1089            Self::Short { count: Some(1) } => write!(f, "short"),
1090            Self::Word { count: Some(1) } => write!(f, "word"),
1091            Self::Byte { count: Some(count) } => write!(f, "byte[{count}]"),
1092            Self::Short { count: Some(count) } => write!(f, "short[{count}]"),
1093            Self::Word { count: Some(count) } => write!(f, "word[{count}]"),
1094            Self::Byte { count: None } => write!(f, "byte[]"),
1095            Self::Short { count: None } => write!(f, "short[]"),
1096            Self::Word { count: None } => write!(f, "word[]"),
1097        }
1098    }
1099}
1100
1101#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1102pub struct SymBss {
1103    pub size: Option<u32>,
1104}
1105
1106#[derive(Debug, Snafu)]
1107pub enum SymBssParseError {
1108    #[snafu(display("{context}: failed to parse size '{value}': {error}\n{backtrace}"))]
1109    ParseBssSize { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
1110    #[snafu(display("{context}: unknown attribute '{key}', must be one of: size:\n{backtrace}'"))]
1111    UnknownBssAttribute { context: ParseContext, key: String, backtrace: Backtrace },
1112}
1113
1114impl SymBss {
1115    fn parse(options: &str, context: &ParseContext) -> Result<Self, SymBssParseError> {
1116        let mut size = None;
1117        if !options.trim().is_empty() {
1118            for option in options.split(',') {
1119                if let Some((key, value)) = option.split_once('=') {
1120                    match key {
1121                        "size" => {
1122                            size = Some(parse_u32(value).map_err(|error| ParseBssSizeSnafu { context, value, error }.build())?)
1123                        }
1124                        _ => return UnknownBssAttributeSnafu { context, key }.fail(),
1125                    }
1126                } else {
1127                    return UnknownBssAttributeSnafu { context, key: option }.fail();
1128                }
1129            }
1130        }
1131        Ok(Self { size })
1132    }
1133}
1134
1135impl Display for SymBss {
1136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1137        if let Some(size) = self.size {
1138            write!(f, "(size={size:#x})")?;
1139        }
1140        Ok(())
1141    }
1142}