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 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 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, 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 pub ambiguous: bool,
516 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, 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 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 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 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}