arm_attr/
lib.rs

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(&section.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    /// Maps list of section indices to a section group
285    pub sections: BTreeMap<&'a [u8], SectionGroup<'a>>,
286}
287
288#[derive(Default)]
289pub struct SectionGroup<'a> {
290    pub attributes: Attributes<'a>,
291    /// Maps list of symbol values to a symbol group
292    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    // Target-related attributes
303    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    // Procedure call-related attributes
324    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    // Miscellaneous attributes
346    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}