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!("_{: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 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 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, 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 pub ambiguous: bool,
521 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, 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 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 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 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}