1#![no_std]
2extern crate alloc;
3
4pub mod enums;
5pub mod error;
6pub mod globals;
7pub mod read;
8pub mod tag;
9
10use alloc::{collections::BTreeMap, string::ToString};
11use core::fmt;
12
13use enums::*;
14use error::{BuildAttrError, PublicAttrsError, ReadError, TagError};
15use read::{read_string, read_u32, Cursor};
16use tag::Tag;
17
18pub use read::Endian;
19
20pub struct BuildAttrs<'a> {
21 data: &'a [u8],
22 endian: Endian,
23}
24
25impl<'a> BuildAttrs<'a> {
26 pub fn new(data: &'a [u8], endian: Endian) -> Result<Self, BuildAttrError> {
27 if data.is_empty() {
28 Err(BuildAttrError::NoData)
29 } else {
30 let attrs = Self { data, endian };
31 let version = attrs.version();
32 if version != b'A' {
33 Err(BuildAttrError::IncompatibleVersion(version))
34 } else {
35 Ok(attrs)
36 }
37 }
38 }
39
40 pub fn version(&self) -> u8 {
41 self.data[0]
42 }
43
44 pub fn subsections(&self) -> SubsectionIter {
45 let data = &self.data[1..];
46 SubsectionIter {
47 cursor: Cursor::new(data),
48 endian: self.endian,
49 }
50 }
51}
52
53pub struct SubsectionIter<'a> {
54 cursor: Cursor<'a>,
55 endian: Endian,
56}
57
58impl<'a> Iterator for SubsectionIter<'a> {
59 type Item = Result<Subsection<'a>, ReadError>;
60
61 fn next(&mut self) -> Option<Self::Item> {
62 let length = match read_u32(&mut self.cursor, self.endian) {
63 Ok(length) => length,
64 Err(ReadError::Eof) => return None,
65 Err(e) => return Some(Err(e)),
66 };
67 let vendor_name = match read_string(&mut self.cursor) {
68 Ok(vendor_name) => vendor_name,
69 Err(ReadError::Eof) => return None,
70 Err(e) => return Some(Err(e)),
71 };
72 let name_size = vendor_name.len() + 1;
73
74 let pos = self.cursor.position();
75 let end = pos + length as usize - name_size - 4;
76 self.cursor.set_position(end);
77 let data = self.cursor.get_ref();
78 if end > data.len() {
79 return Some(Err(ReadError::OutOfBounds));
80 }
81 let data = &data[pos..end];
82 Some(Ok(Subsection {
83 data,
84 endian: self.endian,
85 vendor_name,
86 }))
87 }
88}
89
90pub struct Subsection<'a> {
91 data: &'a [u8],
92 endian: Endian,
93 vendor_name: &'a str,
94}
95
96impl<'a> Subsection<'a> {
97 pub fn is_aeabi(&self) -> bool {
98 self.vendor_name == "aeabi"
99 }
100
101 pub fn data(&self) -> &'a [u8] {
102 self.data
103 }
104
105 pub fn endian(&self) -> Endian {
106 self.endian
107 }
108
109 pub fn vendor_name(&self) -> &str {
110 self.vendor_name
111 }
112}
113
114impl<'a> Subsection<'a> {
115 pub fn into_public_tag_iter(self) -> Result<PublicTagIter<'a>, PublicAttrsError> {
116 if self.is_aeabi() {
117 Ok(PublicTagIter {
118 cursor: Cursor::new(self.data),
119 endian: self.endian,
120 })
121 } else {
122 Err(PublicAttrsError::InvalidName(self.vendor_name.to_string()))
123 }
124 }
125
126 pub fn into_public_attributes(self) -> Result<File<'a>, PublicAttrsError> {
127 let data_len = self.data.len();
128
129 let mut cursor = Cursor::new(self.data);
130 let first_tag = match Tag::read(&mut cursor, self.endian) {
131 Ok(tag) => tag,
132 Err(TagError::Read(ReadError::Eof)) => return Err(PublicAttrsError::NoTags),
133 Err(e) => return Err(PublicAttrsError::Tag(e)),
134 };
135
136 if let Tag::File { end_offset } = first_tag {
137 if end_offset as usize != data_len {
138 return Err(PublicAttrsError::ScopeEndsBeforeParent);
139 }
140 } else {
141 return Err(PublicAttrsError::NoFileTag);
142 }
143
144 let mut file = File::default();
145 let mut attrs = &mut file.attributes;
146 let mut curr_section = None;
147 let mut curr_symbol = None;
148
149 loop {
150 let offset = cursor.position() as u32;
151 let tag = match Tag::read(&mut cursor, self.endian) {
152 Ok(tag) => tag,
153 Err(TagError::Read(ReadError::Eof)) => break,
154 Err(e) => return Err(PublicAttrsError::Tag(e)),
155 };
156
157 if let Some((end_offset, _)) = curr_symbol {
158 if offset >= end_offset {
159 curr_symbol = None;
160 attrs = if let Some((_, sections)) = curr_section {
161 &mut file.sections.entry(sections).or_default().attributes
162 } else {
163 &mut file.attributes
164 };
165 }
166 }
167
168 if let Some((end_offset, _)) = curr_section {
169 if offset >= end_offset {
170 curr_section = None;
171 attrs = &mut file.attributes;
172 }
173 }
174
175 match tag {
176 Tag::File { end_offset: _ } => return Err(PublicAttrsError::DuplicateFileTag),
177 Tag::Section { end_offset, sections } => {
178 if curr_section.is_none() && curr_symbol.is_none() {
179 let section = file.sections.entry(sections).or_default();
180 attrs = &mut section.attributes;
181 curr_section = Some((end_offset, sections));
182 } else {
183 return Err(PublicAttrsError::NotFileScope);
184 }
185 }
186 Tag::Symbol { end_offset, symbols } => {
187 if let Some((section_end, sections)) = &curr_section {
188 if end_offset > *section_end {
189 return Err(PublicAttrsError::ScopeEndsBeforeParent);
190 }
191 let symbol = file.sections.entry(sections).or_default().symbols.entry(symbols).or_default();
192 attrs = &mut symbol.attributes;
193 curr_symbol = Some((end_offset, symbols));
194 } else {
195 return Err(PublicAttrsError::NotSectionScope);
196 }
197 }
198 Tag::CpuRawName(x) => attrs.cpu_raw_name = Some(x),
199 Tag::CpuName(x) => attrs.cpu_name = Some(x),
200 Tag::CpuArch(x) => attrs.cpu_arch = Some(x),
201 Tag::CpuArchProfile(x) => attrs.cpu_arch_profile = Some(x),
202 Tag::ArmIsaUse(x) => attrs.arm_isa_use = Some(x),
203 Tag::ThumbIsaUse(x) => attrs.thumb_isa_use = Some(x),
204 Tag::FpArch(x) => attrs.fp_arch = Some(x),
205 Tag::WmmxArch(x) => attrs.wmmx_arch = Some(x),
206 Tag::AsimdArch(x) => attrs.asimd_arch = Some(x),
207 Tag::PcsConfig(x) => attrs.pcs_config = Some(x),
208 Tag::AbiPcsR9Use(x) => attrs.abi_pcs_r9_use = Some(x),
209 Tag::AbiPcsRwData(x) => attrs.abi_pcs_rw_data = Some(x),
210 Tag::AbiPcsRoData(x) => attrs.abi_pcs_ro_data = Some(x),
211 Tag::AbiPcsGotUse(x) => attrs.abi_pcs_got_use = Some(x),
212 Tag::AbiPcsWcharT(x) => attrs.abi_pcs_wchar_t = Some(x),
213 Tag::AbiFpRounding(x) => attrs.abi_fp_rounding = Some(x),
214 Tag::AbiFpDenormal(x) => attrs.abi_fp_denormal = Some(x),
215 Tag::AbiFpExceptions(x) => attrs.abi_fp_exceptions = Some(x),
216 Tag::AbiFpUserExceptions(x) => attrs.abi_fp_user_exceptions = Some(x),
217 Tag::AbiFpNumberModel(x) => attrs.abi_fp_number_model = Some(x),
218 Tag::AbiAlignNeeded(x) => attrs.abi_align_needed = Some(x),
219 Tag::AbiAlignPreserved(x) => attrs.abi_align_preserved = Some(x),
220 Tag::AbiEnumSize(x) => attrs.abi_enum_size = Some(x),
221 Tag::AbiHardFpUse(x) => attrs.abi_hardfp_use = Some(x),
222 Tag::AbiVfpArgs(x) => attrs.abi_vfp_args = Some(x),
223 Tag::AbiWmmxArgs(x) => attrs.abi_wmmx_args = Some(x),
224 Tag::AbiOptGoals(x) => attrs.abi_opt_goals = Some(x),
225 Tag::AbiFpOptGoals(x) => attrs.abi_fp_opt_goals = Some(x),
226 Tag::Compat(x) => attrs.compat = Some(x),
227 Tag::CpuUnalignedAccess(x) => attrs.cpu_unaligned_access = Some(x),
228 Tag::FpHpExt(x) => attrs.fp_hp_ext = Some(x),
229 Tag::AbiFp16BitFormat(x) => attrs.abi_fp_16bit_format = Some(x),
230 Tag::MpExtUse(x) => attrs.mp_ext_use = Some(x),
231 Tag::DivUse(x) => attrs.div_use = Some(x),
232 Tag::DspExt(x) => attrs.dsp_ext = Some(x),
233 Tag::MveArch(x) => attrs.mve_arch = Some(x),
234 Tag::PacExt(x) => attrs.pac_ext = Some(x),
235 Tag::BtiExt(x) => attrs.bti_ext = Some(x),
236 Tag::AlsoCompatWith(x) => attrs.also_compat_with = Some(x),
237 Tag::Conform(x) => attrs.conform = Some(x),
238 Tag::T2EeUse(x) => attrs.t2ee_use = Some(x),
239 Tag::VirtualUse(x) => attrs.virtual_use = Some(x),
240 Tag::FramePointerUse(x) => attrs.frame_pointer_use = Some(x),
241 Tag::BtiUse(x) => attrs.bti_use = Some(x),
242 Tag::PacretUse(x) => attrs.pacret_use = Some(x),
243 Tag::NoDefaults => attrs.no_defaults = true,
244 }
245 }
246
247 for section in file.sections.values_mut() {
248 if !file.attributes.no_defaults && section.attributes.empty() {
249 section.attributes.inherit(&file.attributes);
250 }
251 if !section.attributes.no_defaults {
252 for symbol in section.symbols.values_mut() {
253 if symbol.attributes.empty() {
254 symbol.attributes.inherit(§ion.attributes);
255 }
256 }
257 }
258 }
259
260 Ok(file)
261 }
262}
263
264pub struct PublicTagIter<'a> {
265 cursor: Cursor<'a>,
266 endian: Endian,
267}
268
269impl<'a> Iterator for PublicTagIter<'a> {
270 type Item = (u32, Tag<'a>);
271
272 fn next(&mut self) -> Option<Self::Item> {
273 let offset = self.cursor.position() as u32;
274 match Tag::read(&mut self.cursor, self.endian) {
275 Ok(tag) => Some((offset, tag)),
276 Err(_) => None,
277 }
278 }
279}
280
281#[derive(Default)]
282pub struct File<'a> {
283 pub attributes: Attributes<'a>,
284 pub sections: BTreeMap<&'a [u8], SectionGroup<'a>>,
286}
287
288#[derive(Default)]
289pub struct SectionGroup<'a> {
290 pub attributes: Attributes<'a>,
291 pub symbols: BTreeMap<&'a [u8], SymbolGroup<'a>>,
293}
294
295#[derive(Default)]
296pub struct SymbolGroup<'a> {
297 pub attributes: Attributes<'a>,
298}
299
300#[derive(Default)]
301pub struct Attributes<'a> {
302 pub cpu_raw_name: Option<&'a str>,
304 pub cpu_name: Option<CpuName<'a>>,
305 pub cpu_arch: Option<CpuArch>,
306 pub cpu_arch_profile: Option<CpuArchProfile>,
307 pub arm_isa_use: Option<ArmIsaUse>,
308 pub thumb_isa_use: Option<ThumbIsaUse>,
309 pub fp_arch: Option<FpArch>,
310 pub wmmx_arch: Option<WmmxArch>,
311 pub asimd_arch: Option<AsimdArch>,
312 pub mve_arch: Option<MveArch>,
313 pub fp_hp_ext: Option<FpHpExt>,
314 pub cpu_unaligned_access: Option<CpuUnalignedAccess>,
315 pub t2ee_use: Option<T2EeUse>,
316 pub virtual_use: Option<VirtualUse>,
317 pub mp_ext_use: Option<MpExtUse>,
318 pub div_use: Option<DivUse>,
319 pub dsp_ext: Option<DspExt>,
320 pub pac_ext: Option<PacExt>,
321 pub bti_ext: Option<BtiExt>,
322
323 pub pcs_config: Option<PcsConfig>,
325 pub abi_pcs_r9_use: Option<AbiPcsR9Use>,
326 pub abi_pcs_rw_data: Option<AbiPcsRwData>,
327 pub abi_pcs_ro_data: Option<AbiPcsRoData>,
328 pub abi_pcs_got_use: Option<AbiPcsGotUse>,
329 pub abi_pcs_wchar_t: Option<AbiPcsWcharT>,
330 pub abi_enum_size: Option<AbiEnumSize>,
331 pub abi_align_needed: Option<AbiAlignNeeded>,
332 pub abi_align_preserved: Option<AbiAlignPreserved>,
333 pub abi_fp_rounding: Option<AbiFpRounding>,
334 pub abi_fp_denormal: Option<AbiFpDenormal>,
335 pub abi_fp_exceptions: Option<AbiFpExceptions>,
336 pub abi_fp_user_exceptions: Option<AbiFpUserExceptions>,
337 pub abi_fp_number_model: Option<AbiFpNumberModel>,
338 pub abi_fp_16bit_format: Option<AbiFp16BitFormat>,
339 pub abi_hardfp_use: Option<AbiHardFpUse>,
340 pub abi_vfp_args: Option<AbiVfpArgs>,
341 pub abi_wmmx_args: Option<AbiWmmxArgs>,
342 pub frame_pointer_use: Option<FramePointerUse>,
343 pub bti_use: Option<BtiUse>,
344
345 pub pacret_use: Option<PacretUse>,
347 pub abi_opt_goals: Option<AbiOptGoals>,
348 pub abi_fp_opt_goals: Option<AbiFpOptGoals>,
349 pub compat: Option<Compat<'a>>,
350 pub also_compat_with: Option<AlsoCompatWith<'a>>,
351 pub conform: Option<Conform<'a>>,
352 pub no_defaults: bool,
353}
354
355impl<'a> Attributes<'a> {
356 pub fn empty(&self) -> bool {
357 self.cpu_raw_name.is_none()
358 && self.cpu_name.is_none()
359 && self.cpu_arch.is_none()
360 && self.cpu_arch_profile.is_none()
361 && self.arm_isa_use.is_none()
362 && self.thumb_isa_use.is_none()
363 && self.fp_arch.is_none()
364 && self.wmmx_arch.is_none()
365 && self.asimd_arch.is_none()
366 && self.mve_arch.is_none()
367 && self.fp_hp_ext.is_none()
368 && self.cpu_unaligned_access.is_none()
369 && self.t2ee_use.is_none()
370 && self.virtual_use.is_none()
371 && self.mp_ext_use.is_none()
372 && self.div_use.is_none()
373 && self.dsp_ext.is_none()
374 && self.pac_ext.is_none()
375 && self.bti_ext.is_none()
376 && self.pcs_config.is_none()
377 && self.abi_pcs_r9_use.is_none()
378 && self.abi_pcs_rw_data.is_none()
379 && self.abi_pcs_ro_data.is_none()
380 && self.abi_pcs_got_use.is_none()
381 && self.abi_pcs_wchar_t.is_none()
382 && self.abi_enum_size.is_none()
383 && self.abi_align_needed.is_none()
384 && self.abi_align_preserved.is_none()
385 && self.abi_fp_rounding.is_none()
386 && self.abi_fp_denormal.is_none()
387 && self.abi_fp_exceptions.is_none()
388 && self.abi_fp_user_exceptions.is_none()
389 && self.abi_fp_number_model.is_none()
390 && self.abi_fp_16bit_format.is_none()
391 && self.abi_hardfp_use.is_none()
392 && self.abi_vfp_args.is_none()
393 && self.abi_wmmx_args.is_none()
394 && self.frame_pointer_use.is_none()
395 && self.bti_use.is_none()
396 && self.pacret_use.is_none()
397 && self.abi_opt_goals.is_none()
398 && self.abi_fp_opt_goals.is_none()
399 && self.compat.is_none()
400 && self.also_compat_with.is_none()
401 && self.conform.is_none()
402 }
403
404 fn inherit(&mut self, from: &Attributes<'a>) {
405 macro_rules! inherit {
406 ($to:ident, $from:ident, $tag:ident) => {
407 $to.$tag = $to.$tag.or($from.$tag)
408 };
409 }
410 inherit!(self, from, cpu_raw_name);
411 inherit!(self, from, cpu_name);
412 inherit!(self, from, cpu_arch);
413 inherit!(self, from, cpu_arch_profile);
414 inherit!(self, from, arm_isa_use);
415 inherit!(self, from, thumb_isa_use);
416 inherit!(self, from, fp_arch);
417 inherit!(self, from, wmmx_arch);
418 inherit!(self, from, asimd_arch);
419 inherit!(self, from, mve_arch);
420 inherit!(self, from, fp_hp_ext);
421 inherit!(self, from, cpu_unaligned_access);
422 inherit!(self, from, t2ee_use);
423 inherit!(self, from, virtual_use);
424 inherit!(self, from, mp_ext_use);
425 inherit!(self, from, div_use);
426 inherit!(self, from, dsp_ext);
427 inherit!(self, from, pac_ext);
428 inherit!(self, from, bti_ext);
429 inherit!(self, from, pcs_config);
430 inherit!(self, from, abi_pcs_r9_use);
431 inherit!(self, from, abi_pcs_rw_data);
432 inherit!(self, from, abi_pcs_ro_data);
433 inherit!(self, from, abi_pcs_got_use);
434 inherit!(self, from, abi_pcs_wchar_t);
435 inherit!(self, from, abi_enum_size);
436 inherit!(self, from, abi_align_needed);
437 inherit!(self, from, abi_align_preserved);
438 inherit!(self, from, abi_fp_rounding);
439 inherit!(self, from, abi_fp_denormal);
440 inherit!(self, from, abi_fp_exceptions);
441 inherit!(self, from, abi_fp_user_exceptions);
442 inherit!(self, from, abi_fp_number_model);
443 inherit!(self, from, abi_fp_16bit_format);
444 inherit!(self, from, abi_hardfp_use);
445 inherit!(self, from, abi_vfp_args);
446 inherit!(self, from, abi_wmmx_args);
447 inherit!(self, from, frame_pointer_use);
448 inherit!(self, from, bti_use);
449 inherit!(self, from, pacret_use);
450 inherit!(self, from, abi_opt_goals);
451 inherit!(self, from, abi_fp_opt_goals);
452 inherit!(self, from, compat);
453 if self.also_compat_with.is_none() {
454 self.also_compat_with.clone_from(&from.also_compat_with);
455 }
456 inherit!(self, from, conform);
457 }
458
459 pub fn display(&self, options: AttributeDisplayOptions) -> AttributeScopeDisplay {
460 AttributeScopeDisplay { scope: self, options }
461 }
462}
463
464pub struct AttributeScopeDisplay<'a> {
465 scope: &'a Attributes<'a>,
466 options: AttributeDisplayOptions,
467}
468
469pub struct AttributeDisplayOptions {
470 pub indent: usize,
471 pub show_defaults: bool,
472 pub show_target: bool,
473 pub show_pcs: bool,
474 pub show_misc: bool,
475}
476
477impl<'a> AttributeScopeDisplay<'a> {
478 fn display_field<T: fmt::Display + Default>(
479 &self,
480 f: &mut fmt::Formatter<'_>,
481 field: &str,
482 value: &Option<T>,
483 ) -> fmt::Result {
484 if let Some(value) = value {
485 writeln!(f, "{}{} : {}", format_args!("{: >1$}", "", self.options.indent), field, value)
486 } else if self.options.show_defaults {
487 let value = T::default();
488 writeln!(
489 f,
490 "{}{} : [default] {}",
491 format_args!("{: >1$}", "", self.options.indent),
492 field,
493 value
494 )
495 } else {
496 Ok(())
497 }
498 }
499
500 fn display_quote(&self, f: &mut fmt::Formatter<'_>, field: &str, value: &Option<&str>) -> fmt::Result {
501 if let Some(value) = value {
502 writeln!(
503 f,
504 "{}{} : \"{}\"",
505 format_args!("{: >1$}", "", self.options.indent),
506 field,
507 value
508 )
509 } else if self.options.show_defaults {
510 writeln!(
511 f,
512 "{}{} : [default] \"\"",
513 format_args!("{: >1$}", "", self.options.indent),
514 field
515 )
516 } else {
517 Ok(())
518 }
519 }
520}
521
522impl<'a> fmt::Display for AttributeScopeDisplay<'a> {
523 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
524 let scope = self.scope;
525 if self.options.show_target {
526 self.display_quote(f, "CPU raw name .........", &scope.cpu_raw_name)?;
527 self.display_field(f, "CPU name .............", &scope.cpu_name)?;
528 self.display_field(f, "CPU arch .............", &scope.cpu_arch)?;
529 self.display_field(f, "CPU arch profile .....", &scope.cpu_arch_profile)?;
530 self.display_field(f, "ARM ISA use ..........", &scope.arm_isa_use)?;
531 self.display_field(f, "Thumb ISA use ........", &scope.thumb_isa_use)?;
532 self.display_field(f, "FP arch ..............", &scope.fp_arch)?;
533 self.display_field(f, "WMMX arch ............", &scope.wmmx_arch)?;
534 self.display_field(f, "Advanced SIMD arch ...", &scope.asimd_arch)?;
535 self.display_field(f, "MVE arch .............", &scope.mve_arch)?;
536 self.display_field(f, "FP HP extension ......", &scope.fp_hp_ext)?;
537 self.display_field(f, "Unaligned access .....", &scope.cpu_unaligned_access)?;
538 self.display_field(f, "T2EE use .............", &scope.t2ee_use)?;
539 self.display_field(f, "Virtualization use ...", &scope.virtual_use)?;
540 self.display_field(f, "MP extension use .....", &scope.mp_ext_use)?;
541 self.display_field(f, "DIV use ..............", &scope.div_use)?;
542 self.display_field(f, "DSP use ..............", &scope.dsp_ext)?;
543 self.display_field(f, "PAC extension ........", &scope.pac_ext)?;
544 self.display_field(f, "BTI extension ........", &scope.bti_ext)?;
545 }
546 if self.options.show_pcs {
547 self.display_field(f, "PCS config ...........", &scope.pcs_config)?;
548 self.display_field(f, "PCS R9 use ...........", &scope.abi_pcs_r9_use)?;
549 self.display_field(f, "PCS RW data ..........", &scope.abi_pcs_rw_data)?;
550 self.display_field(f, "PCS RO data ..........", &scope.abi_pcs_ro_data)?;
551 self.display_field(f, "PCS GOT use ..........", &scope.abi_pcs_got_use)?;
552 self.display_field(f, "PCS wchar_t ..........", &scope.abi_pcs_wchar_t)?;
553 self.display_field(f, "Enum size ............", &scope.abi_enum_size)?;
554 self.display_field(f, "Align needed .........", &scope.abi_align_needed)?;
555 self.display_field(f, "Align preserved ......", &scope.abi_align_preserved)?;
556 self.display_field(f, "FP rounding ..........", &scope.abi_fp_rounding)?;
557 self.display_field(f, "FP denormal ..........", &scope.abi_fp_denormal)?;
558 self.display_field(f, "FP exceptions ........", &scope.abi_fp_exceptions)?;
559 self.display_field(f, "FP user exceptions ...", &scope.abi_fp_user_exceptions)?;
560 self.display_field(f, "FP number format .....", &scope.abi_fp_number_model)?;
561 self.display_field(f, "FP 16-bit format .....", &scope.abi_fp_16bit_format)?;
562 self.display_field(f, "FP hardware use ......", &scope.abi_hardfp_use)?;
563 self.display_field(f, "VFP args .............", &scope.abi_vfp_args)?;
564 self.display_field(f, "WMMX args ............", &scope.abi_wmmx_args)?;
565 self.display_field(f, "Frame Pointer use ....", &scope.frame_pointer_use)?;
566 self.display_field(f, "BTI use ..............", &scope.bti_use)?;
567 }
568 if self.options.show_misc {
569 self.display_field(f, "PACRET use ...........", &scope.pacret_use)?;
570 self.display_field(f, "Optimization goals ...", &scope.abi_opt_goals)?;
571 self.display_field(f, "FP optimization goals ", &scope.abi_fp_opt_goals)?;
572 self.display_field(f, "Compatibility ........", &scope.compat)?;
573 self.display_field(f, "Also compatible with .", &scope.also_compat_with)?;
574 self.display_field(f, "Conformance ..........", &scope.conform)?;
575 }
576 Ok(())
577 }
578}