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