Skip to main content

ds_decomp/config/
symbol.rs

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