1use std::{
2 backtrace::Backtrace,
3 collections::{BTreeMap, HashMap, btree_map, hash_map},
4 fmt::Display,
5 io::{self, BufWriter, Write},
6 num::{NonZeroUsize, ParseIntError},
7 ops::Range,
8 path::Path,
9 slice,
10};
11
12use snafu::{Snafu, ensure};
13
14use super::{ParseContext, config::Config, iter_attributes, module::ModuleKind};
15use crate::{
16 analysis::{functions::Function, jump_table::JumpTable},
17 config::{CommentedLine, Comments},
18 util::{
19 io::{FileError, create_file},
20 parse::parse_u32,
21 },
22};
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>>(
56 config_path: P,
57 config: &Config,
58 ) -> Result<Self, SymbolMapsParseError> {
59 let config_path = config_path.as_ref();
60
61 let mut symbol_maps = SymbolMaps::new();
62 symbol_maps
63 .get_mut(ModuleKind::Arm9)
64 .load(config_path.join(&config.main_module.symbols))?;
65 for autoload in &config.autoloads {
66 symbol_maps
67 .get_mut(ModuleKind::Autoload(autoload.kind))
68 .load(config_path.join(&autoload.module.symbols))?;
69 }
70 for overlay in &config.overlays {
71 symbol_maps
72 .get_mut(ModuleKind::Overlay(overlay.id))
73 .load(config_path.join(&overlay.module.symbols))?;
74 }
75
76 Ok(symbol_maps)
77 }
78
79 pub fn to_files<P: AsRef<Path>>(
80 &self,
81 config: &Config,
82 config_path: P,
83 ) -> Result<(), SymbolMapsWriteError> {
84 let config_path = config_path.as_ref();
85 self.get(ModuleKind::Arm9)
86 .ok_or_else(|| SymbolMapNotFoundSnafu { module: ModuleKind::Arm9 }.build())?
87 .to_file(config_path.join(&config.main_module.symbols))?;
88 for autoload in &config.autoloads {
89 let module = ModuleKind::Autoload(autoload.kind);
90 self.get(module)
91 .ok_or_else(|| SymbolMapNotFoundSnafu { module }.build())?
92 .to_file(config_path.join(&autoload.module.symbols))?;
93 }
94 for overlay in &config.overlays {
95 let module = ModuleKind::Overlay(overlay.id);
96 self.get(module)
97 .ok_or_else(|| SymbolMapNotFoundSnafu { module }.build())?
98 .to_file(config_path.join(&overlay.module.symbols))?;
99 }
100
101 Ok(())
102 }
103
104 pub fn iter(&self) -> impl Iterator<Item = (ModuleKind, &'_ SymbolMap)> {
105 self.symbol_maps.iter().map(|(module, symbol_map)| (*module, symbol_map))
106 }
107
108 pub fn iter_mut(&mut self) -> impl Iterator<Item = (ModuleKind, &'_ mut SymbolMap)> {
109 self.symbol_maps.iter_mut().map(|(module, symbol_map)| (*module, symbol_map))
110 }
111
112 pub fn find_symbols_by_name(
113 &self,
114 name: &str,
115 ) -> impl Iterator<Item = (ModuleKind, SymbolId, &Symbol)> {
116 self.symbol_maps.iter().flat_map(|(module, symbol_map)| {
117 symbol_map
118 .for_name(name)
119 .into_iter()
120 .flat_map(move |symbols| symbols.map(|(id, symbol)| (*module, id, symbol)))
121 })
122 }
123}
124
125#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
126pub struct SymbolId(NonZeroUsize);
127
128#[deprecated(note = "use SymbolId instead")]
129pub type SymbolIndex = SymbolId;
130
131pub struct SymbolMap {
132 symbols: SymbolVec,
133 symbols_by_address: BTreeMap<u32, Vec<SymbolId>>,
134 symbols_by_name: HashMap<String, Vec<SymbolId>>,
135}
136
137#[derive(Debug, Snafu)]
138pub enum SymbolMapParseError {
139 #[snafu(transparent)]
140 File { source: FileError },
141 #[snafu(transparent)]
142 Io { source: io::Error },
143 #[snafu(transparent)]
144 SymbolParse { source: SymbolParseError },
145}
146
147#[derive(Debug, Snafu)]
148pub enum SymbolMapWriteError {
149 #[snafu(transparent)]
150 File { source: FileError },
151 #[snafu(transparent)]
152 Io { source: io::Error },
153}
154
155#[derive(Debug, Snafu)]
156pub enum SymbolMapError {
157 #[snafu(display("multiple symbols at {address:#010x}: {name}, {other_name}:\n{backtrace}"))]
158 MultipleSymbols { address: u32, name: String, other_name: String, backtrace: Backtrace },
159 #[snafu(display(
160 "multiple symbols with name '{name}': {old_address:#010x}, {new_address:#010x}:\n{backtrace}"
161 ))]
162 DuplicateName { name: String, new_address: u32, old_address: u32, backtrace: Backtrace },
163 #[snafu(display("no symbol at {address:#010x} to rename to '{new_name}':\n{backtrace}"))]
164 NoSymbolToRename { address: u32, new_name: String, backtrace: Backtrace },
165 #[snafu(display(
166 "there must be exactly one symbol at {address:#010x} to rename to '{new_name}':\n{backtrace}"
167 ))]
168 RenameMultiple { address: u32, new_name: String, backtrace: Backtrace },
169}
170
171impl SymbolMap {
172 pub fn new() -> Self {
173 Self::from_symbols(vec![])
174 }
175
176 pub fn from_symbols(symbols: Vec<Symbol>) -> Self {
177 let mut symbols_by_address = BTreeMap::<u32, Vec<_>>::new();
178 let mut symbols_by_name = HashMap::<String, Vec<_>>::new();
179
180 let symbols = SymbolVec::from_symbols(symbols);
181
182 for (id, symbol) in symbols.iter() {
183 symbols_by_address.entry(symbol.addr).or_default().push(*id);
184 symbols_by_name.entry(symbol.name.clone()).or_default().push(*id);
185 }
186
187 Self { symbols, symbols_by_address, symbols_by_name }
188 }
189
190 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, SymbolMapParseError> {
191 let mut symbol_map = Self::new();
192 symbol_map.load(path)?;
193 Ok(symbol_map)
194 }
195
196 pub fn load<P: AsRef<Path>>(&mut self, path: P) -> Result<(), SymbolMapParseError> {
197 let path = path.as_ref();
198 let mut context = ParseContext { file_path: path.to_str().unwrap().to_string(), row: 0 };
199
200 let lines = CommentedLine::read(path)?;
201 for line in lines {
202 let line = line?;
203 context.row = line.row;
204
205 let Some(symbol) = Symbol::parse(line, &context)? else { continue };
206 self.add(symbol);
207 }
208 Ok(())
209 }
210
211 pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), SymbolMapWriteError> {
212 let path = path.as_ref();
213
214 let file = create_file(path)?;
215 let mut writer = BufWriter::new(file);
216
217 for ids in self.symbols_by_address.values() {
218 for &id in ids {
219 let symbol = self.get(id).unwrap();
220 if symbol.should_write() {
221 writeln!(writer, "{symbol}")?;
222 }
223 }
224 }
225
226 Ok(())
227 }
228
229 pub fn for_address(
230 &self,
231 address: u32,
232 ) -> Option<impl DoubleEndedIterator<Item = (SymbolId, &Symbol)>> {
233 Some(self.symbols_by_address.get(&address)?.iter().map(|&id| (id, self.get(id).unwrap())))
234 }
235
236 pub fn by_address(&self, address: u32) -> Result<Option<(SymbolId, &Symbol)>, SymbolMapError> {
237 let Some(mut symbols) = self.for_address(address) else {
238 return Ok(None);
239 };
240 let (id, symbol) = symbols.next().unwrap();
241 if let Some((_, other)) = symbols.next() {
242 return MultipleSymbolsSnafu {
243 address,
244 name: symbol.name.clone(),
245 other_name: other.name.clone(),
246 }
247 .fail();
248 }
249 Ok(Some((id, symbol)))
250 }
251
252 pub fn first_at_address(&self, address: u32) -> Option<(SymbolId, &Symbol)> {
253 self.for_address(address)?.next()
254 }
255
256 pub fn for_name(
257 &self,
258 name: &str,
259 ) -> Option<impl DoubleEndedIterator<Item = (SymbolId, &Symbol)>> {
260 Some(self.symbols_by_name.get(name)?.iter().map(|&id| (id, self.get(id).unwrap())))
261 }
262
263 pub fn by_name(&self, name: &str) -> Result<Option<(SymbolId, &Symbol)>, SymbolMapError> {
264 let Some(mut symbols) = self.for_name(name) else {
265 return Ok(None);
266 };
267 let (id, symbol) = symbols.next().unwrap();
268 if let Some((_, other)) = symbols.next() {
269 return DuplicateNameSnafu { name, new_address: symbol.addr, old_address: other.addr }
270 .fail();
271 }
272 Ok(Some((id, symbol)))
273 }
274
275 pub fn iter_by_address(&self, range: Range<u32>) -> SymbolIterator<'_> {
276 SymbolIterator {
277 symbols_by_address: self.symbols_by_address.range(range),
278 ids: [].iter(),
279 symbols: &self.symbols,
280 }
281 }
282
283 pub fn first_symbol_before(&self, max_address: u32) -> Option<Vec<(SymbolId, &Symbol)>> {
285 self.symbols_by_address.range(0..=max_address).rev().find_map(|(_, ids)| {
286 let symbols = ids
287 .iter()
288 .filter_map(|&id| {
289 let symbol = self.get(id).unwrap();
290 symbol.is_external().then_some((id, symbol))
291 })
292 .collect::<Vec<_>>();
293 (!symbols.is_empty()).then_some(symbols)
294 })
295 }
296
297 pub fn first_symbol_after(&self, min_address: u32) -> Option<Vec<(SymbolId, &Symbol)>> {
299 self.symbols_by_address.range(min_address + 1..).find_map(|(_, ids)| {
300 let symbols = ids
301 .iter()
302 .filter_map(|&id| {
303 let symbol = self.get(id).unwrap();
304 symbol.is_external().then_some((id, symbol))
305 })
306 .collect::<Vec<_>>();
307 (!symbols.is_empty()).then_some(symbols)
308 })
309 }
310
311 pub fn iter(&self) -> impl Iterator<Item = &'_ Symbol> {
312 self.symbols_by_address.values().flat_map(|ids| ids.iter()).map(|&id| self.get(id).unwrap())
313 }
314
315 #[deprecated(note = "use ids_by_address instead")]
316 pub fn indices_by_address(&self) -> impl Iterator<Item = &SymbolId> {
317 self.ids_by_address()
318 }
319
320 pub fn ids_by_address(&self) -> impl Iterator<Item = &SymbolId> {
321 self.symbols_by_address.values().flat_map(|ids| ids.iter())
322 }
323
324 pub fn get(&self, id: SymbolId) -> Option<&Symbol> {
325 self.symbols.get(id)
326 }
327
328 pub fn get_mut(&mut self, id: SymbolId) -> Option<&mut Symbol> {
329 self.symbols.get_mut(id)
330 }
331
332 pub fn get_symbol_containing(
334 &self,
335 addr: u32,
336 section_end: u32,
337 ) -> Result<Option<(&Symbol, u32)>, SymbolMapError> {
338 let Some(symbols) = self.first_symbol_before(addr) else {
339 return Ok(None);
340 };
341 let (_, symbol) = symbols.first().unwrap();
342 let Some(symbols) = self.first_symbol_after(symbol.addr) else {
343 return Ok(Some((symbol, symbol.size(section_end))));
344 };
345 let next_symbol = symbols.first().unwrap().1;
346
347 Ok(Some((symbol, symbol.size(next_symbol.addr.min(section_end)))))
348 }
349
350 pub fn add(&mut self, symbol: Symbol) -> (SymbolId, &Symbol) {
351 let (id, symbol) = self.symbols.add(symbol);
352 self.symbols_by_address.entry(symbol.addr).or_default().push(id);
353 self.symbols_by_name.entry(symbol.name.clone()).or_default().push(id);
354 (id, symbol)
355 }
356
357 pub fn add_if_new_address(
358 &mut self,
359 symbol: Symbol,
360 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
361 if self.symbols_by_address.contains_key(&symbol.addr) {
362 Ok(self.by_address(symbol.addr)?.unwrap())
363 } else {
364 Ok(self.add(symbol))
365 }
366 }
367
368 pub fn get_function(
369 &self,
370 address: u32,
371 ) -> Result<Option<(SymFunction, &Symbol)>, SymbolMapError> {
372 let Some(symbols) = self.for_address(address & !1) else {
373 return Ok(None);
374 };
375 let mut symbols = symbols.filter(|(_, sym)| matches!(sym.kind, SymbolKind::Function(_)));
376 let Some((_, symbol)) = symbols.next() else {
377 return Ok(None);
378 };
379 if let Some((_, other)) = symbols.next() {
380 return MultipleSymbolsSnafu {
381 address,
382 name: symbol.name.clone(),
383 other_name: other.name.clone(),
384 }
385 .fail();
386 }
387
388 Ok(match symbol.kind {
389 SymbolKind::Function(function) => Some((function, symbol)),
390 _ => None,
391 })
392 }
393
394 pub fn get_function_mut(
395 &mut self,
396 address: u32,
397 ) -> Result<Option<&mut Symbol>, SymbolMapError> {
398 let Some(symbols) = self.symbols_by_address.get_mut(&(address & !1)) else {
399 return Ok(None);
400 };
401
402 let mut symbols = symbols
403 .iter()
404 .filter(|&&id| matches!(self.symbols.get(id).unwrap().kind, SymbolKind::Function(_)));
405 let Some(&id) = symbols.next() else {
406 return Ok(None);
407 };
408 if let Some(&other_id) = symbols.next() {
409 let symbol = self.get(id).unwrap();
410 let other = self.get(other_id).unwrap();
411 return MultipleSymbolsSnafu {
412 address,
413 name: symbol.name.clone(),
414 other_name: other.name.clone(),
415 }
416 .fail();
417 }
418 let symbol = self.get_mut(id).unwrap();
419
420 Ok(Some(symbol))
421 }
422
423 pub fn get_function_containing(&self, addr: u32) -> Option<(SymFunction, &Symbol)> {
424 self.symbols_by_address
425 .range(0..=addr)
426 .rev()
427 .filter_map(|(_, ids)| {
428 let &id = ids.first()?;
429 let symbol = self.get(id).unwrap();
430 if let SymbolKind::Function(func) = symbol.kind {
431 Some((func, symbol))
432 } else {
433 None
434 }
435 })
436 .take_while(|(func, sym)| func.contains(sym, addr))
437 .next()
438 }
439
440 pub fn functions(&self) -> impl Iterator<Item = (SymFunction, &'_ Symbol)> {
441 FunctionSymbolIterator {
442 symbols_by_address: self.symbols_by_address.values(),
443 ids: [].iter(),
444 symbols: &self.symbols,
445 }
446 }
447
448 pub fn clone_functions(&self) -> Vec<(SymFunction, Symbol)> {
449 self.functions().map(|(function, symbol)| (function, symbol.clone())).collect()
450 }
451
452 pub fn data_symbols(&self) -> impl Iterator<Item = (SymData, &'_ Symbol)> {
453 self.symbols.iter().filter_map(|(_, symbol)| {
454 if let SymbolKind::Data(sym_data) = symbol.kind {
455 Some((sym_data, symbol))
456 } else {
457 None
458 }
459 })
460 }
461
462 pub fn bss_symbols(&self) -> impl Iterator<Item = (SymBss, &'_ Symbol)> {
463 self.symbols.iter().filter_map(|(_, symbol)| {
464 if let SymbolKind::Bss(sym_bss) = symbol.kind {
465 Some((sym_bss, symbol))
466 } else {
467 None
468 }
469 })
470 }
471
472 pub fn label_name(addr: u32) -> String {
473 format!(".L_{addr:08x}")
474 }
475
476 pub fn add_label(
477 &mut self,
478 addr: u32,
479 thumb: bool,
480 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
481 let name = Self::label_name(addr);
482 self.add_if_new_address(Symbol::new_label(name, addr, thumb))
483 }
484
485 pub fn add_external_label(
487 &mut self,
488 addr: u32,
489 thumb: bool,
490 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
491 let name = Self::label_name(addr);
492 self.add_if_new_address(Symbol::new_external_label(name, addr, thumb))
493 }
494
495 pub fn get_label(&self, addr: u32) -> Result<Option<&Symbol>, SymbolMapError> {
496 Ok(self
497 .by_address(addr)?
498 .and_then(|(_, s)| (matches!(s.kind, SymbolKind::Label { .. })).then_some(s)))
499 }
500
501 pub fn add_pool_constant(&mut self, addr: u32) -> Result<(SymbolId, &Symbol), SymbolMapError> {
502 let name = Self::label_name(addr);
503 self.add_if_new_address(Symbol::new_pool_constant(name, addr))
504 }
505
506 pub fn get_pool_constant(&self, addr: u32) -> Result<Option<&Symbol>, SymbolMapError> {
507 Ok(self
508 .by_address(addr)?
509 .and_then(|(_, s)| (s.kind == SymbolKind::PoolConstant).then_some(s)))
510 }
511
512 pub fn get_jump_table(
513 &self,
514 addr: u32,
515 ) -> Result<Option<(SymJumpTable, &Symbol)>, SymbolMapError> {
516 Ok(self.by_address(addr)?.and_then(|(_, s)| match s.kind {
517 SymbolKind::JumpTable(jump_table) => Some((jump_table, s)),
518 _ => None,
519 }))
520 }
521
522 fn make_unambiguous(&mut self, addr: u32) -> Result<(), SymbolMapError> {
523 if let Some(id) = self
524 .by_address(addr)?
525 .filter(|(_, symbol)| matches!(symbol.kind, SymbolKind::Data(_) | SymbolKind::Bss(_)))
526 .map(|(id, _)| id)
527 {
528 self.get_mut(id).unwrap().ambiguous = false;
529 }
530 Ok(())
531 }
532
533 pub fn add_function(&mut self, function: &Function) -> (SymbolId, &Symbol) {
534 self.add(Symbol::from_function(function))
535 }
536
537 pub fn add_unknown_function(
538 &mut self,
539 name: String,
540 addr: u32,
541 thumb: bool,
542 ) -> (SymbolId, &Symbol) {
543 self.add(Symbol::new_unknown_function(name, addr & !1, thumb))
544 }
545
546 pub fn add_jump_table(
547 &mut self,
548 table: &JumpTable,
549 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
550 let name = Self::label_name(table.address);
551 self.add_if_new_address(Symbol::new_jump_table(name, table.address, table.size, table.code))
552 }
553
554 pub fn add_data(
555 &mut self,
556 name: Option<String>,
557 addr: u32,
558 data: SymData,
559 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
560 let name = name.unwrap_or_else(|| Self::label_name(addr));
561 self.make_unambiguous(addr)?;
562 self.add_if_new_address(Symbol::new_data(name, addr, data, false))
563 }
564
565 pub fn add_ambiguous_data(
566 &mut self,
567 name: Option<String>,
568 addr: u32,
569 data: SymData,
570 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
571 let name = name.unwrap_or_else(|| Self::label_name(addr));
572 self.add_if_new_address(Symbol::new_data(name, addr, data, true))
573 }
574
575 pub fn add_skip_data(
576 &mut self,
577 name: Option<String>,
578 addr: u32,
579 data: SymData,
580 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
581 let name = name.unwrap_or_else(|| Self::label_name(addr));
582 self.add_if_new_address(Symbol::new_skip_data(name, addr, data, true))
583 }
584
585 pub fn get_data(&self, addr: u32) -> Result<Option<(SymData, &Symbol)>, SymbolMapError> {
586 Ok(self.by_address(addr)?.and_then(|(_, s)| match s.kind {
587 SymbolKind::Data(data) => Some((data, s)),
588 _ => None,
589 }))
590 }
591
592 pub fn add_bss(
593 &mut self,
594 name: Option<String>,
595 addr: u32,
596 data: SymBss,
597 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
598 let name = name.unwrap_or_else(|| Self::label_name(addr));
599 self.make_unambiguous(addr)?;
600 self.add_if_new_address(Symbol::new_bss(name, addr, data, false))
601 }
602
603 pub fn add_ambiguous_bss(
604 &mut self,
605 name: Option<String>,
606 addr: u32,
607 data: SymBss,
608 ) -> Result<(SymbolId, &Symbol), SymbolMapError> {
609 let name = name.unwrap_or_else(|| Self::label_name(addr));
610 self.add_if_new_address(Symbol::new_bss(name, addr, data, true))
611 }
612
613 pub fn rename_by_address(
617 &mut self,
618 address: u32,
619 new_name: &str,
620 ) -> Result<bool, SymbolMapError> {
621 let symbol_ids = self
622 .symbols_by_address
623 .get(&address)
624 .ok_or_else(|| NoSymbolToRenameSnafu { address, new_name }.build())?;
625 ensure!(symbol_ids.len() == 1, RenameMultipleSnafu { address, new_name });
626
627 let symbol_id = symbol_ids[0];
628 let name = &self.symbols.get(symbol_id).unwrap().name;
629 if name == new_name {
630 return Ok(false);
631 }
632
633 match self.symbols_by_name.entry(name.clone()) {
634 hash_map::Entry::Occupied(mut entry) => {
635 let symbol_ids = entry.get_mut();
636 if symbol_ids.len() == 1 {
637 entry.remove();
638 } else {
639 let pos = symbol_ids.iter().position(|&id| id == symbol_id).unwrap();
641 symbol_ids.remove(pos);
642 }
643 }
644 hash_map::Entry::Vacant(_) => {
645 panic!(
646 "No symbol name entry found for '{name}' when trying to rename to '{new_name}'"
647 );
648 }
649 }
650
651 match self.symbols_by_name.entry(new_name.to_string()) {
652 hash_map::Entry::Occupied(mut entry) => {
653 entry.get_mut().push(symbol_id);
654 }
655 hash_map::Entry::Vacant(entry) => {
656 entry.insert(vec![symbol_id]);
657 }
658 }
659
660 self.get_mut(symbol_id).unwrap().name = new_name.to_string();
661
662 Ok(true)
663 }
664
665 pub fn remove(&mut self, id: SymbolId) -> Option<Symbol> {
666 let symbol = self.symbols.remove(id)?;
667
668 match self.symbols_by_address.entry(symbol.addr) {
669 btree_map::Entry::Vacant(_) => {}
670 btree_map::Entry::Occupied(mut entry) => {
671 let ids = entry.get_mut();
672 ids.retain(|&id_| id_ != id);
673 if ids.is_empty() {
674 entry.remove();
675 }
676 }
677 }
678
679 match self.symbols_by_name.entry(symbol.name.clone()) {
680 hash_map::Entry::Vacant(_) => {}
681 hash_map::Entry::Occupied(mut entry) => {
682 let ids = entry.get_mut();
683 ids.retain(|&id_| id_ != id);
684 if ids.is_empty() {
685 entry.remove();
686 }
687 }
688 }
689
690 Some(symbol)
691 }
692}
693
694struct SymbolVec(Vec<(SymbolId, Symbol)>);
695
696impl SymbolVec {
697 fn from_symbols(symbols: Vec<Symbol>) -> Self {
698 let symbols = symbols
699 .into_iter()
700 .enumerate()
701 .map(|(i, symbol)| (SymbolId(NonZeroUsize::MIN.saturating_add(i)), symbol))
702 .collect::<Vec<_>>();
703 Self(symbols)
704 }
705
706 fn iter(&self) -> impl Iterator<Item = &(SymbolId, Symbol)> {
707 self.0.iter()
708 }
709
710 fn index_of(&self, id: SymbolId) -> Option<usize> {
711 self.0.binary_search_by_key(&id, |(id, _)| *id).ok()
712 }
713
714 fn get(&self, id: SymbolId) -> Option<&Symbol> {
715 let index = self.index_of(id)?;
716 Some(&self.0[index].1)
717 }
718
719 fn get_mut(&mut self, id: SymbolId) -> Option<&mut Symbol> {
720 let index = self.index_of(id)?;
721 Some(&mut self.0[index].1)
722 }
723
724 fn next_id(&self) -> SymbolId {
725 if let Some((last, _)) = self.0.last() {
726 SymbolId(last.0.saturating_add(1))
727 } else {
728 SymbolId(NonZeroUsize::MIN)
729 }
730 }
731
732 fn add(&mut self, symbol: Symbol) -> (SymbolId, &Symbol) {
733 let id = self.next_id();
734 self.0.push((id, symbol));
735 (id, &self.0.last().unwrap().1)
736 }
737
738 fn remove(&mut self, id: SymbolId) -> Option<Symbol> {
739 let index = self.index_of(id)?;
740 Some(self.0.remove(index).1)
741 }
742}
743
744pub struct SymbolIterator<'a> {
745 symbols_by_address: btree_map::Range<'a, u32, Vec<SymbolId>>,
746 ids: slice::Iter<'a, SymbolId>,
747 symbols: &'a SymbolVec,
748}
749
750impl<'a> Iterator for SymbolIterator<'a> {
751 type Item = (SymbolId, &'a Symbol);
752
753 fn next(&mut self) -> Option<Self::Item> {
754 loop {
755 if let Some(&id) = self.ids.next() {
756 break Some((id, self.symbols.get(id).unwrap()));
757 } else if let Some((_, ids)) = self.symbols_by_address.next() {
758 self.ids = ids.iter();
759 continue;
760 } else {
761 break None;
762 }
763 }
764 }
765}
766
767impl DoubleEndedIterator for SymbolIterator<'_> {
768 fn next_back(&mut self) -> Option<Self::Item> {
769 loop {
770 if let Some(&id) = self.ids.next_back() {
771 break Some((id, self.symbols.get(id).unwrap()));
772 } else if let Some((_, ids)) = self.symbols_by_address.next_back() {
773 self.ids = ids.iter();
774 continue;
775 } else {
776 break None;
777 }
778 }
779 }
780}
781
782pub struct FunctionSymbolIterator<'a, I: Iterator<Item = &'a Vec<SymbolId>>> {
783 symbols_by_address: I, ids: slice::Iter<'a, SymbolId>,
785 symbols: &'a SymbolVec,
786}
787
788impl<'a, I: Iterator<Item = &'a Vec<SymbolId>>> FunctionSymbolIterator<'a, I> {
789 fn next_function(&mut self) -> Option<(SymFunction, &'a Symbol)> {
790 for &id in self.ids.by_ref() {
791 let symbol = self.symbols.get(id).unwrap();
792 if let SymbolKind::Function(function) = symbol.kind {
793 return Some((function, symbol));
794 }
795 }
796 None
797 }
798}
799
800impl<'a, I: Iterator<Item = &'a Vec<SymbolId>>> Iterator for FunctionSymbolIterator<'a, I> {
801 type Item = (SymFunction, &'a Symbol);
802
803 fn next(&mut self) -> Option<Self::Item> {
804 if let Some(function) = self.next_function() {
805 return Some(function);
806 }
807 while let Some(ids) = self.symbols_by_address.next() {
808 self.ids = ids.iter();
809 if let Some(function) = self.next_function() {
810 return Some(function);
811 }
812 }
813 None
814 }
815}
816
817#[derive(Clone)]
818pub struct Symbol {
819 pub name: String,
820 pub kind: SymbolKind,
821 pub addr: u32,
822 pub ambiguous: bool,
824 pub local: bool,
826 pub skip: bool,
829 pub comments: Comments,
830}
831
832#[derive(Debug, Snafu)]
833pub enum SymbolParseError {
834 #[snafu(transparent)]
835 SymbolKindParse { source: SymbolKindParseError },
836 #[snafu(display("{context}: failed to parse address '{value}': {error}\n{backtrace}"))]
837 ParseAddress {
838 context: ParseContext,
839 value: String,
840 error: ParseIntError,
841 backtrace: Backtrace,
842 },
843 #[snafu(display(
844 "{context}: expected symbol attribute 'kind' or 'addr' but got '{key}':\n{backtrace}"
845 ))]
846 UnknownAttribute { context: ParseContext, key: String, backtrace: Backtrace },
847 #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
848 MissingAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
849}
850
851impl Symbol {
852 fn parse(
853 line: CommentedLine,
854 context: &ParseContext,
855 ) -> Result<Option<Self>, SymbolParseError> {
856 let mut words = line.text.split_whitespace();
857 let Some(name) = words.next() else { return Ok(None) };
858
859 let mut kind = None;
860 let mut addr = None;
861 let mut ambiguous = false;
862 let mut local = false;
863 for (key, value) in iter_attributes(words) {
864 match key {
865 "kind" => kind = Some(SymbolKind::parse(value, context)?),
866 "addr" => {
867 addr = Some(
868 parse_u32(value)
869 .map_err(|error| ParseAddressSnafu { context, value, error }.build())?,
870 )
871 }
872 "ambiguous" => ambiguous = true,
873 "local" => local = true,
874 _ => return UnknownAttributeSnafu { context, key }.fail(),
875 }
876 }
877
878 let name = name.to_string();
879 let kind =
880 kind.ok_or_else(|| MissingAttributeSnafu { context, attribute: "kind" }.build())?;
881 let addr =
882 addr.ok_or_else(|| MissingAttributeSnafu { context, attribute: "addr" }.build())?;
883
884 Ok(Some(Symbol {
885 name,
886 kind,
887 addr,
888 ambiguous,
889 local,
890 skip: false,
891 comments: line.comments,
892 }))
893 }
894
895 fn should_write(&self) -> bool {
896 !self.skip && self.kind.should_write()
897 }
898
899 pub fn from_function(function: &Function) -> Self {
900 Self {
901 name: function.name().to_string(),
902 kind: SymbolKind::Function(SymFunction {
903 mode: InstructionMode::from_thumb(function.is_thumb()),
904 size: function.size(),
905 unknown: false,
906 }),
907 addr: function.first_instruction_address() & !1,
908 ambiguous: false,
909 local: false,
910 skip: false,
911 comments: Comments::new(),
912 }
913 }
914
915 pub fn new_unknown_function(name: String, addr: u32, thumb: bool) -> Self {
916 Self {
917 name,
918 kind: SymbolKind::Function(SymFunction {
919 mode: InstructionMode::from_thumb(thumb),
920 size: 0,
921 unknown: true,
922 }),
923 addr,
924 ambiguous: false,
925 local: false,
926 skip: false,
927 comments: Comments::new(),
928 }
929 }
930
931 pub fn new_label(name: String, addr: u32, thumb: bool) -> Self {
932 Self {
933 name,
934 kind: SymbolKind::Label(SymLabel {
935 external: false,
936 mode: InstructionMode::from_thumb(thumb),
937 }),
938 addr,
939 ambiguous: false,
940 local: true,
941 skip: false,
942 comments: Comments::new(),
943 }
944 }
945
946 pub fn new_external_label(name: String, addr: u32, thumb: bool) -> Self {
947 Self {
948 name,
949 kind: SymbolKind::Label(SymLabel {
950 external: true,
951 mode: InstructionMode::from_thumb(thumb),
952 }),
953 addr,
954 ambiguous: false,
955 local: false,
956 skip: false,
957 comments: Comments::new(),
958 }
959 }
960
961 pub fn new_pool_constant(name: String, addr: u32) -> Self {
962 Self {
963 name,
964 kind: SymbolKind::PoolConstant,
965 addr,
966 ambiguous: false,
967 local: true,
968 skip: false,
969 comments: Comments::new(),
970 }
971 }
972
973 pub fn new_jump_table(name: String, addr: u32, size: u32, code: bool) -> Self {
974 Self {
975 name,
976 kind: SymbolKind::JumpTable(SymJumpTable { size, code }),
977 addr,
978 ambiguous: false,
979 local: true,
980 skip: false,
981 comments: Comments::new(),
982 }
983 }
984
985 pub fn new_data(name: String, addr: u32, data: SymData, ambiguous: bool) -> Symbol {
986 Self {
987 name,
988 kind: SymbolKind::Data(data),
989 addr,
990 ambiguous,
991 local: false,
992 skip: false,
993 comments: Comments::new(),
994 }
995 }
996
997 pub fn new_skip_data(name: String, addr: u32, data: SymData, ambiguous: bool) -> Symbol {
998 Self {
999 name,
1000 kind: SymbolKind::Data(data),
1001 addr,
1002 ambiguous,
1003 local: false,
1004 skip: true,
1005 comments: Comments::new(),
1006 }
1007 }
1008
1009 pub fn new_bss(name: String, addr: u32, data: SymBss, ambiguous: bool) -> Symbol {
1010 Self {
1011 name,
1012 kind: SymbolKind::Bss(data),
1013 addr,
1014 ambiguous,
1015 local: false,
1016 skip: false,
1017 comments: Comments::new(),
1018 }
1019 }
1020
1021 pub fn size(&self, max_address: u32) -> u32 {
1022 self.kind.size(max_address - self.addr)
1023 }
1024
1025 pub fn is_external(&self) -> bool {
1026 match self.kind {
1027 SymbolKind::Label(SymLabel { external, .. }) => external,
1028 SymbolKind::PoolConstant => false,
1029 SymbolKind::JumpTable(_) => false,
1030 _ => true,
1031 }
1032 }
1033}
1034
1035impl Display for Symbol {
1036 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1037 write!(f, "{}", self.comments.display_pre_comments())?;
1038 write!(f, "{} kind:{} addr:{:#010x}", self.name, self.kind, self.addr)?;
1039 if self.local {
1040 write!(f, " local")?;
1041 }
1042 if self.ambiguous {
1043 write!(f, " ambiguous")?;
1044 }
1045 write!(f, "{}", self.comments.display_post_comment())?;
1046 Ok(())
1047 }
1048}
1049
1050#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1051pub enum SymbolKind {
1052 Undefined,
1053 Function(SymFunction),
1054 Label(SymLabel),
1055 PoolConstant,
1056 JumpTable(SymJumpTable),
1057 Data(SymData),
1058 Bss(SymBss),
1059}
1060
1061#[derive(Debug, Snafu)]
1062pub enum SymbolKindParseError {
1063 #[snafu(transparent)]
1064 SymFunctionParse { source: SymFunctionParseError },
1065 #[snafu(transparent)]
1066 SymDataParse { source: SymDataParseError },
1067 #[snafu(transparent)]
1068 SymBssParse { source: SymBssParseError },
1069 #[snafu(transparent)]
1070 SymLabelParse { source: SymLabelParseError },
1071 #[snafu(display(
1072 "{context}: unknown symbol kind '{kind}', must be one of: function, data, bss, label:\n{backtrace}"
1073 ))]
1074 UnknownKind { context: ParseContext, kind: String, backtrace: Backtrace },
1075}
1076
1077impl SymbolKind {
1078 fn parse(text: &str, context: &ParseContext) -> Result<Self, SymbolKindParseError> {
1079 let (kind, options) = text.split_once('(').unwrap_or((text, ""));
1080 let options = options.strip_suffix(')').unwrap_or(options);
1081
1082 match kind {
1083 "function" => Ok(Self::Function(SymFunction::parse(options, context)?)),
1084 "data" => Ok(Self::Data(SymData::parse(options, context)?)),
1085 "bss" => Ok(Self::Bss(SymBss::parse(options, context)?)),
1086 "label" => Ok(Self::Label(SymLabel::parse(options, context)?)),
1087 _ => UnknownKindSnafu { context, kind }.fail(),
1088 }
1089 }
1090
1091 fn should_write(&self) -> bool {
1092 match self {
1093 SymbolKind::Undefined => false,
1094 SymbolKind::Function(_) => true,
1095 SymbolKind::Label(label) => label.external,
1096 SymbolKind::PoolConstant => false,
1097 SymbolKind::JumpTable(_) => false,
1098 SymbolKind::Data(_) => true,
1099 SymbolKind::Bss(_) => true,
1100 }
1101 }
1102
1103 pub fn size(&self, max_size: u32) -> u32 {
1104 match self {
1105 SymbolKind::Undefined => 0,
1106 SymbolKind::Function(function) => function.size,
1107 SymbolKind::Label(_) => 0,
1108 SymbolKind::PoolConstant => 0, SymbolKind::JumpTable(_) => 0,
1110 SymbolKind::Data(data) => data.size().unwrap_or(max_size),
1111 SymbolKind::Bss(bss) => bss.size.unwrap_or(max_size),
1112 }
1113 }
1114}
1115
1116impl Display for SymbolKind {
1117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1118 match self {
1119 SymbolKind::Undefined => {}
1120 SymbolKind::Function(function) => write!(f, "function({function})")?,
1121 SymbolKind::Data(data) => write!(f, "data({data})")?,
1122 SymbolKind::Bss(bss) => write!(f, "bss{bss}")?,
1123 SymbolKind::Label(label) => write!(f, "label({label})")?,
1124 SymbolKind::PoolConstant => {}
1125 SymbolKind::JumpTable(_) => {}
1126 }
1127 Ok(())
1128 }
1129}
1130
1131#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1132pub struct SymFunction {
1133 pub mode: InstructionMode,
1134 pub size: u32,
1135 pub unknown: bool,
1138}
1139
1140#[derive(Debug, Snafu)]
1141pub enum SymFunctionParseError {
1142 #[snafu(display("{context}: failed to parse size '{value}': {error}\n{backtrace}"))]
1143 ParseFunctionSize {
1144 context: ParseContext,
1145 value: String,
1146 error: ParseIntError,
1147 backtrace: Backtrace,
1148 },
1149 #[snafu(display(
1150 "{context}: unknown function attribute '{key}', must be one of: size, unknown, arm, thumb:\n{backtrace}"
1151 ))]
1152 UnknownFunctionAttribute { context: ParseContext, key: String, backtrace: Backtrace },
1153 #[snafu(transparent)]
1154 InstructionModeParse { source: InstructionModeParseError },
1155 #[snafu(display("{context}: function must have an instruction mode: arm or thumb"))]
1156 MissingInstructionMode { context: ParseContext, backtrace: Backtrace },
1157 #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
1158 MissingFunctionAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
1159}
1160
1161impl SymFunction {
1162 fn parse(options: &str, context: &ParseContext) -> Result<Self, SymFunctionParseError> {
1163 let mut size = None;
1164 let mut mode = None;
1165 let mut unknown = false;
1166 for option in options.split(',') {
1167 if let Some((key, value)) = option.split_once('=') {
1168 match key {
1169 "size" => {
1170 size = Some(parse_u32(value).map_err(|error| {
1171 ParseFunctionSizeSnafu { context, value, error }.build()
1172 })?);
1173 }
1174 _ => return UnknownFunctionAttributeSnafu { context, key }.fail(),
1175 }
1176 } else {
1177 match option {
1178 "unknown" => unknown = true,
1179 _ => mode = Some(InstructionMode::parse(option, context)?),
1180 }
1181 }
1182 }
1183
1184 Ok(Self {
1185 mode: mode.ok_or_else(|| MissingInstructionModeSnafu { context }.build())?,
1186 size: size.ok_or_else(|| {
1187 MissingFunctionAttributeSnafu { context, attribute: "size" }.build()
1188 })?,
1189 unknown,
1190 })
1191 }
1192
1193 fn contains(self, sym: &Symbol, addr: u32) -> bool {
1194 if self.unknown {
1195 sym.addr == addr
1197 } else {
1198 let start = sym.addr;
1199 let end = start + self.size;
1200 addr >= start && addr < end
1201 }
1202 }
1203}
1204
1205impl Display for SymFunction {
1206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1207 write!(f, "{},size={:#x}", self.mode, self.size)?;
1208 if self.unknown {
1209 write!(f, ",unknown")?;
1210 }
1211 Ok(())
1212 }
1213}
1214
1215#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1216pub struct SymLabel {
1217 pub external: bool,
1221 pub mode: InstructionMode,
1222}
1223
1224#[derive(Debug, Snafu)]
1225pub enum SymLabelParseError {
1226 #[snafu(transparent)]
1227 InstructionModeParse { source: InstructionModeParseError },
1228}
1229
1230impl SymLabel {
1231 fn parse(options: &str, context: &ParseContext) -> Result<Self, SymLabelParseError> {
1232 Ok(Self { external: true, mode: InstructionMode::parse(options, context)? })
1233 }
1234}
1235
1236impl Display for SymLabel {
1237 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1238 write!(f, "{}", self.mode)
1239 }
1240}
1241
1242#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1243pub enum InstructionMode {
1244 Arm,
1245 Thumb,
1246}
1247
1248#[derive(Debug, Snafu)]
1249pub enum InstructionModeParseError {
1250 #[snafu(display(
1251 "{context}: expected instruction mode 'arm' or 'thumb' but got '{value}':\n{backtrace}"
1252 ))]
1253 UnknownInstructionMode { context: ParseContext, value: String, backtrace: Backtrace },
1254}
1255
1256impl InstructionMode {
1257 fn parse(value: &str, context: &ParseContext) -> Result<Self, InstructionModeParseError> {
1258 match value {
1259 "arm" => Ok(Self::Arm),
1260 "thumb" => Ok(Self::Thumb),
1261 _ => UnknownInstructionModeSnafu { context, value }.fail(),
1262 }
1263 }
1264
1265 pub fn from_thumb(thumb: bool) -> Self {
1266 if thumb { Self::Thumb } else { Self::Arm }
1267 }
1268
1269 pub fn into_thumb(self) -> Option<bool> {
1270 match self {
1271 Self::Arm => Some(false),
1272 Self::Thumb => Some(true),
1273 }
1274 }
1275}
1276
1277impl Display for InstructionMode {
1278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1279 match self {
1280 Self::Arm => write!(f, "arm"),
1281 Self::Thumb => write!(f, "thumb"),
1282 }
1283 }
1284}
1285
1286#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1287pub struct SymJumpTable {
1288 pub size: u32,
1289 pub code: bool,
1290}
1291
1292#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1293pub enum SymData {
1294 Any,
1295 Byte { count: Option<u32> },
1296 Short { count: Option<u32> },
1297 Word { count: Option<u32> },
1298}
1299
1300#[derive(Debug, Snafu)]
1301pub enum SymDataParseError {
1302 #[snafu(display(
1303 "{context}: expected data kind 'any', 'byte', 'short' or 'word' but got nothing:\n{backtrace}"
1304 ))]
1305 EmptyData { context: ParseContext, backtrace: Backtrace },
1306 #[snafu(display("{context}: failed to parse count '{value}': {error}\n{backtrace}"))]
1307 ParseCount { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
1308 #[snafu(display("{context}: unexpected characters after ']':\n{backtrace}"))]
1309 CharacterAfterArray { context: ParseContext, backtrace: Backtrace },
1310 #[snafu(display("{context}: data type 'any' cannot be an array:\n{backtrace}"))]
1311 ArrayOfAny { context: ParseContext, backtrace: Backtrace },
1312 #[snafu(display(
1313 "{context}: expected data kind 'any', 'byte', 'short' or 'word' but got '{kind}':\n{backtrace}"
1314 ))]
1315 UnknownDataKind { context: ParseContext, kind: String, backtrace: Backtrace },
1316}
1317
1318impl SymData {
1319 fn parse(kind: &str, context: &ParseContext) -> Result<Self, SymDataParseError> {
1320 if kind.is_empty() {
1321 return EmptyDataSnafu { context }.fail();
1322 }
1323
1324 let (kind, rest) = kind.split_once('[').unwrap_or((kind, ""));
1325 let (count, rest) = rest
1326 .split_once(']')
1327 .map(|(count, rest)| {
1328 let count = if count.is_empty() {
1329 Ok(None)
1330 } else {
1331 parse_u32(count)
1332 .map(Some)
1333 .map_err(|error| ParseCountSnafu { context, value: count, error }.build())
1334 };
1335 (count, rest)
1336 })
1337 .unwrap_or((Ok(Some(1)), rest));
1338 let count = count?;
1339
1340 if !rest.is_empty() {
1341 return CharacterAfterArraySnafu { context }.fail();
1342 }
1343
1344 match kind {
1345 "any" => {
1346 if count == Some(1) {
1347 Ok(Self::Any)
1348 } else {
1349 ArrayOfAnySnafu { context }.fail()
1350 }
1351 }
1352 "short" => Ok(Self::Short { count }),
1353 "byte" => Ok(Self::Byte { count }),
1354 "word" => Ok(Self::Word { count }),
1355 kind => UnknownDataKindSnafu { context, kind }.fail(),
1356 }
1357 }
1358
1359 pub fn count(self) -> Option<u32> {
1360 match self {
1361 Self::Any => None,
1362 Self::Byte { count } => count,
1363 Self::Short { count } => count,
1364 Self::Word { count } => count,
1365 }
1366 }
1367
1368 pub fn element_size(self) -> u32 {
1369 match self {
1370 Self::Any => 1,
1371 Self::Byte { .. } => 1,
1372 Self::Short { .. } => 2,
1373 Self::Word { .. } => 4,
1374 }
1375 }
1376
1377 pub fn size(&self) -> Option<u32> {
1378 self.count().map(|count| self.element_size() * count)
1379 }
1380}
1381
1382impl Display for SymData {
1383 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1384 match self {
1385 Self::Any => write!(f, "any"),
1386 Self::Byte { count: Some(1) } => write!(f, "byte"),
1387 Self::Short { count: Some(1) } => write!(f, "short"),
1388 Self::Word { count: Some(1) } => write!(f, "word"),
1389 Self::Byte { count: Some(count) } => write!(f, "byte[{count}]"),
1390 Self::Short { count: Some(count) } => write!(f, "short[{count}]"),
1391 Self::Word { count: Some(count) } => write!(f, "word[{count}]"),
1392 Self::Byte { count: None } => write!(f, "byte[]"),
1393 Self::Short { count: None } => write!(f, "short[]"),
1394 Self::Word { count: None } => write!(f, "word[]"),
1395 }
1396 }
1397}
1398
1399#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1400pub struct SymBss {
1401 pub size: Option<u32>,
1402}
1403
1404#[derive(Debug, Snafu)]
1405pub enum SymBssParseError {
1406 #[snafu(display("{context}: failed to parse size '{value}': {error}\n{backtrace}"))]
1407 ParseBssSize {
1408 context: ParseContext,
1409 value: String,
1410 error: ParseIntError,
1411 backtrace: Backtrace,
1412 },
1413 #[snafu(display("{context}: unknown attribute '{key}', must be one of: size:\n{backtrace}'"))]
1414 UnknownBssAttribute { context: ParseContext, key: String, backtrace: Backtrace },
1415}
1416
1417impl SymBss {
1418 fn parse(options: &str, context: &ParseContext) -> Result<Self, SymBssParseError> {
1419 let mut size = None;
1420 if !options.trim().is_empty() {
1421 for option in options.split(',') {
1422 if let Some((key, value)) = option.split_once('=') {
1423 match key {
1424 "size" => {
1425 size = Some(parse_u32(value).map_err(|error| {
1426 ParseBssSizeSnafu { context, value, error }.build()
1427 })?);
1428 }
1429 _ => return UnknownBssAttributeSnafu { context, key }.fail(),
1430 }
1431 } else {
1432 return UnknownBssAttributeSnafu { context, key: option }.fail();
1433 }
1434 }
1435 }
1436 Ok(Self { size })
1437 }
1438}
1439
1440impl Display for SymBss {
1441 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1442 if let Some(size) = self.size {
1443 write!(f, "(size={size:#x})")?;
1444 }
1445 Ok(())
1446 }
1447}