ds_decomp/config/
symbol.rs

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