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