1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
#![allow(non_upper_case_globals)]

use std::io::Cursor;

use crate::{
    enums::*,
    error::TagError,
    globals::*,
    read::{read_string, read_u32, read_u8, read_uleb128, read_uleb128_list, Endian},
};

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum Tag<'a> {
    /// Tag_File
    File { end_offset: u32 },
    /// Tag_Section
    Section { end_offset: u32, sections: &'a [u8] },
    /// Tag_Symbol
    Symbol { end_offset: u32, symbols: &'a [u8] },
    /// Tag_CPU_raw_name
    CpuRawName(&'a str),
    /// Tag_CPU_name
    CpuName(CpuName<'a>),
    /// Tag_CPU_arch
    CpuArch(CpuArch),
    /// Tag_CPU_arch_profile
    CpuArchProfile(CpuArchProfile),
    /// Tag_ARM_ISA_use
    ArmIsaUse(ArmIsaUse),
    /// Tag_THUMB_ISA_use
    ThumbIsaUse(ThumbIsaUse),
    /// Tag_FP_arch
    FpArch(FpArch),
    /// Tag_WMMX_arch
    WmmxArch(WmmxArch),
    /// Tag_Advanced_SIMD_arch
    AsimdArch(AsimdArch),
    /// Tag_PCS_config
    PcsConfig(PcsConfig),
    /// Tag_ABI_PCS_R9_use
    AbiPcsR9Use(AbiPcsR9Use),
    /// Tag_ABI_PCS_RW_data
    AbiPcsRwData(AbiPcsRwData),
    /// Tag_ABI_PCS_RO_data
    AbiPcsRoData(AbiPcsRoData),
    /// Tag_ABI_PCS_GOT_use
    AbiPcsGotUse(AbiPcsGotUse),
    /// Tag_ABI_PCS_wchar_t
    AbiPcsWcharT(AbiPcsWcharT),
    /// Tag_ABI_FP_rounding
    AbiFpRounding(AbiFpRounding),
    /// Tag_ABI_FP_denormal
    AbiFpDenormal(AbiFpDenormal),
    /// Tag_ABI_FP_exceptions
    AbiFpExceptions(AbiFpExceptions),
    /// Tag_ABI_FP_user_exceptions
    AbiFpUserExceptions(AbiFpUserExceptions),
    /// Tag_ABI_FP_number_model
    AbiFpNumberModel(AbiFpNumberModel),
    /// Tag_ABI_align_needed
    AbiAlignNeeded(AbiAlignNeeded),
    /// Tag_ABI_align_preserved
    AbiAlignPreserved(AbiAlignPreserved),
    /// Tag_ABI_enum_size
    AbiEnumSize(AbiEnumSize),
    /// Tag_ABI_HardFP_use
    AbiHardFpUse(AbiHardFpUse),
    /// Tag_ABI_VFP_args
    AbiVfpArgs(AbiVfpArgs),
    /// Tag_ABI_WMMX_args
    AbiWmmxArgs(AbiWmmxArgs),
    /// Tag_ABI_optimization_goals
    AbiOptGoals(AbiOptGoals),
    /// Tag_ABI_FP_optimization_goals
    AbiFpOptGoals(AbiFpOptGoals),
    /// Tag_compatibility
    Compat(Compat<'a>),
    /// Tag_CPU_unaligned_access
    CpuUnalignedAccess(CpuUnalignedAccess),
    /// Tag_FP_HP_extension
    FpHpExt(FpHpExt),
    /// Tag_ABI_FP_16bit_format
    AbiFp16BitFormat(AbiFp16BitFormat),
    /// Tag_MPextension_use
    MpExtUse(MpExtUse),
    /// Tag_DIV_use
    DivUse(DivUse),
    /// Tag_DSP_extension
    DspExt(DspExt),
    /// Tag_MVE_arch
    MveArch(MveArch),
    /// Tag_PAC_extension
    PacExt(PacExt),
    /// Tag_BTI_extension
    BtiExt(BtiExt),
    /// Tag_nodefaults
    NoDefaults,
    /// Tag_also_compatible_with
    AlsoCompatWith(AlsoCompatWith<'a>),
    /// Tag_conformance
    Conform(Conform<'a>),
    /// Tag_T2EE_use
    T2EeUse(T2EeUse),
    /// Tag_Virtualization_use
    VirtualUse(VirtualUse),
    /// Tag_FramePointer_use
    FramePointerUse(FramePointerUse),
    /// Tag_BTI_use
    BtiUse(BtiUse),
    /// Tag_PACRET_use
    PacretUse(PacretUse),
}

impl<'a> Tag<'a> {
    pub fn is_uleb128(&self) -> bool {
        !matches!(
            self,
            Tag::File { end_offset: _ }
                | Tag::Section {
                    end_offset: _,
                    sections: _
                }
                | Tag::Symbol {
                    end_offset: _,
                    symbols: _
                }
                | Tag::CpuRawName(_)
                | Tag::CpuName(_)
                | Tag::Compat(_)
                | Tag::AlsoCompatWith(_)
                | Tag::Conform(_)
        )
    }

    pub fn is_scope(&self) -> bool {
        matches!(
            self,
            Tag::File { end_offset: _ }
                | Tag::Section {
                    end_offset: _,
                    sections: _
                }
                | Tag::Symbol {
                    end_offset: _,
                    symbols: _
                }
        )
    }

    pub fn raw_tag(&self) -> u8 {
        match self {
            Tag::File { end_offset: _ } => Tag_File,
            Tag::Section {
                end_offset: _,
                sections: _,
            } => Tag_Section,
            Tag::Symbol {
                end_offset: _,
                symbols: _,
            } => Tag_Symbol,
            Tag::CpuRawName(_) => Tag_CPU_raw_name,
            Tag::CpuName(_) => Tag_CPU_name,
            Tag::CpuArch(_) => Tag_CPU_arch,
            Tag::CpuArchProfile(_) => Tag_CPU_arch_profile,
            Tag::ArmIsaUse(_) => Tag_ARM_ISA_use,
            Tag::ThumbIsaUse(_) => Tag_THUMB_ISA_use,
            Tag::FpArch(_) => Tag_FP_arch,
            Tag::WmmxArch(_) => Tag_WMMX_arch,
            Tag::AsimdArch(_) => Tag_Advanced_SIMD_arch,
            Tag::PcsConfig(_) => Tag_PCS_config,
            Tag::AbiPcsR9Use(_) => Tag_ABI_PCS_R9_use,
            Tag::AbiPcsRwData(_) => Tag_ABI_PCS_RW_data,
            Tag::AbiPcsRoData(_) => Tag_ABI_PCS_RO_data,
            Tag::AbiPcsGotUse(_) => Tag_ABI_PCS_GOT_use,
            Tag::AbiPcsWcharT(_) => Tag_ABI_PCS_wchar_t,
            Tag::AbiFpRounding(_) => Tag_ABI_FP_rounding,
            Tag::AbiFpDenormal(_) => Tag_ABI_FP_denormal,
            Tag::AbiFpExceptions(_) => Tag_ABI_FP_exceptions,
            Tag::AbiFpUserExceptions(_) => Tag_ABI_FP_user_exceptions,
            Tag::AbiFpNumberModel(_) => Tag_ABI_FP_number_model,
            Tag::AbiAlignNeeded(_) => Tag_ABI_align_needed,
            Tag::AbiAlignPreserved(_) => Tag_ABI_align_preserved,
            Tag::AbiEnumSize(_) => Tag_ABI_enum_size,
            Tag::AbiHardFpUse(_) => Tag_ABI_HardFP_use,
            Tag::AbiVfpArgs(_) => Tag_ABI_VFP_args,
            Tag::AbiWmmxArgs(_) => Tag_ABI_WMMX_args,
            Tag::AbiOptGoals(_) => Tag_ABI_optimization_goals,
            Tag::AbiFpOptGoals(_) => Tag_ABI_FP_optimization_goals,
            Tag::Compat(_) => Tag_compatibility,
            Tag::CpuUnalignedAccess(_) => Tag_CPU_unaligned_access,
            Tag::FpHpExt(_) => Tag_FP_HP_extension,
            Tag::AbiFp16BitFormat(_) => Tag_ABI_FP_16bit_format,
            Tag::MpExtUse(_) => Tag_MPextension_use,
            Tag::DivUse(_) => Tag_DIV_use,
            Tag::DspExt(_) => Tag_DSP_extension,
            Tag::MveArch(_) => Tag_MVE_arch,
            Tag::PacExt(_) => Tag_PAC_extension,
            Tag::BtiExt(_) => Tag_BTI_extension,
            Tag::NoDefaults => Tag_nodefaults,
            Tag::AlsoCompatWith(_) => Tag_also_compatible_with,
            Tag::Conform(_) => Tag_conformance,
            Tag::T2EeUse(_) => Tag_T2EE_use,
            Tag::VirtualUse(_) => Tag_Virtualization_use,
            Tag::FramePointerUse(_) => Tag_FramePointer_use,
            Tag::BtiUse(_) => Tag_BTI_use,
            Tag::PacretUse(_) => Tag_PACRET_use,
        }
    }

    pub(crate) fn read(cursor: &mut Cursor<&'a [u8]>, endian: Endian) -> Result<Self, TagError> {
        let pos = cursor.position() as u32;
        let tag = read_uleb128(cursor).map_err(TagError::Read)?;
        let tag = match tag {
            Tag_File => Tag::File {
                end_offset: pos + read_u32(cursor, endian).map_err(TagError::Read)?,
            },
            Tag_Section => Tag::Section {
                end_offset: pos + read_u32(cursor, endian).map_err(TagError::Read)?,
                sections: read_uleb128_list(cursor).map_err(TagError::Read)?,
            },
            Tag_Symbol => Tag::Symbol {
                end_offset: pos + read_u32(cursor, endian).map_err(TagError::Read)?,
                symbols: read_uleb128_list(cursor).map_err(TagError::Read)?,
            },
            Tag_CPU_raw_name => Tag::CpuRawName(read_string(cursor).map_err(TagError::Read)?),
            Tag_CPU_name => Tag::CpuName(CpuName::from(read_string(cursor).map_err(TagError::Read)?)),
            Tag_CPU_arch => Tag::CpuArch(CpuArch::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_CPU_arch_profile => Tag::CpuArchProfile(CpuArchProfile::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ARM_ISA_use => Tag::ArmIsaUse(ArmIsaUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_THUMB_ISA_use => Tag::ThumbIsaUse(ThumbIsaUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_FP_arch => Tag::FpArch(FpArch::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_WMMX_arch => Tag::WmmxArch(WmmxArch::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_Advanced_SIMD_arch => Tag::AsimdArch(AsimdArch::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_PCS_config => Tag::PcsConfig(PcsConfig::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_PCS_R9_use => Tag::AbiPcsR9Use(AbiPcsR9Use::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_PCS_RW_data => Tag::AbiPcsRwData(AbiPcsRwData::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_PCS_RO_data => Tag::AbiPcsRoData(AbiPcsRoData::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_PCS_GOT_use => Tag::AbiPcsGotUse(AbiPcsGotUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_PCS_wchar_t => Tag::AbiPcsWcharT(AbiPcsWcharT::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_FP_rounding => Tag::AbiFpRounding(AbiFpRounding::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_FP_denormal => Tag::AbiFpDenormal(AbiFpDenormal::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_FP_exceptions => {
                Tag::AbiFpExceptions(AbiFpExceptions::from(read_uleb128(cursor).map_err(TagError::Read)?))
            }
            Tag_ABI_FP_user_exceptions => {
                Tag::AbiFpUserExceptions(AbiFpUserExceptions::from(read_uleb128(cursor).map_err(TagError::Read)?))
            }
            Tag_ABI_FP_number_model => {
                Tag::AbiFpNumberModel(AbiFpNumberModel::from(read_uleb128(cursor).map_err(TagError::Read)?))
            }
            Tag_ABI_align_needed => Tag::AbiAlignNeeded(AbiAlignNeeded::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_align_preserved => {
                Tag::AbiAlignPreserved(AbiAlignPreserved::from(read_uleb128(cursor).map_err(TagError::Read)?))
            }
            Tag_ABI_enum_size => Tag::AbiEnumSize(AbiEnumSize::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_HardFP_use => Tag::AbiHardFpUse(AbiHardFpUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_VFP_args => Tag::AbiVfpArgs(AbiVfpArgs::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_WMMX_args => Tag::AbiWmmxArgs(AbiWmmxArgs::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_optimization_goals => Tag::AbiOptGoals(AbiOptGoals::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_FP_optimization_goals => {
                Tag::AbiFpOptGoals(AbiFpOptGoals::from(read_uleb128(cursor).map_err(TagError::Read)?))
            }
            Tag_compatibility => {
                let flag = read_uleb128(cursor).map_err(TagError::Read)?;
                Tag::Compat(Compat::new(
                    flag,
                    if flag != 0 {
                        read_string(cursor).map_err(TagError::Read)?
                    } else {
                        ""
                    },
                ))
            }
            Tag_CPU_unaligned_access => {
                Tag::CpuUnalignedAccess(CpuUnalignedAccess::from(read_uleb128(cursor).map_err(TagError::Read)?))
            }
            Tag_FP_HP_extension => Tag::FpHpExt(FpHpExt::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_ABI_FP_16bit_format => {
                Tag::AbiFp16BitFormat(AbiFp16BitFormat::from(read_uleb128(cursor).map_err(TagError::Read)?))
            }
            Tag_MPextension_use => Tag::MpExtUse(MpExtUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_DIV_use => Tag::DivUse(DivUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_DSP_extension => Tag::DspExt(DspExt::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_MVE_arch => Tag::MveArch(MveArch::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_PAC_extension => Tag::PacExt(PacExt::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_BTI_extension => Tag::BtiExt(BtiExt::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_nodefaults => {
                let ignored = read_u8(cursor).map_err(TagError::Read)?;
                if ignored != 0 {
                    return Err(TagError::ExpectedNull);
                }
                Tag::NoDefaults
            }
            Tag_also_compatible_with => {
                let sub_tag = Tag::read(cursor, endian)?;
                if sub_tag.is_uleb128() {
                    let null = read_u8(cursor).map_err(TagError::Read)?;
                    if null != 0 {
                        return Err(TagError::ExpectedNull);
                    }
                }
                if sub_tag.is_scope() {
                    return Err(TagError::NestedScopeTag);
                }
                Tag::AlsoCompatWith(AlsoCompatWith::new(sub_tag))
            }
            Tag_conformance => Tag::Conform(Conform::from(read_string(cursor).map_err(TagError::Read)?)),
            Tag_T2EE_use => Tag::T2EeUse(T2EeUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_Virtualization_use => Tag::VirtualUse(VirtualUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_FramePointer_use => Tag::FramePointerUse(FramePointerUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_BTI_use => Tag::BtiUse(BtiUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            Tag_PACRET_use => Tag::PacretUse(PacretUse::from(read_uleb128(cursor).map_err(TagError::Read)?)),
            _ => return Err(TagError::IncompatibleTagValue(tag)),
        };
        Ok(tag)
    }
}