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