charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
//! Default configuration objects and all configuration-related types.

use super::consts::config::ConfigInstructions;
use super::instructions::*;

// -----------------------------------------------------------------------------------------------
// Config
// -----------------------------------------------------------------------------------------------

/// Main configuration object.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct Config {
    /// Global configuration.
    ///
    /// This is where the default behavior is set. Values in this structure
    /// act as a fallback if there is no per-instruction settings.
    pub global: ConfigGlobal,
    /// Per-instruction settings that override the default behavior in the global config.
    pub instructions: ConfigInstructions,
}

impl Config {
    /// Creates a new configuration object with default values.
    pub fn new() -> Self {
        Self::default()
    }
}

/// Type that represents the global configuration.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct ConfigGlobal {
    /// Global syntax rules.
    pub syntax: FormatSyntaxGlobal,
    /// Global qualifier rules.
    pub qualifier: FormatQualifier,
    /// Global aliases rules.
    pub aliases: FormatAliasGlobal,
}

impl ConfigGlobal {
    /// Creates a new global configuration object.
    pub fn new() -> Self {
        Self::default()
    }
}

/// Type that represents the configuration of an instruction.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct ConfigInstruction<A, E> {
    /// Per-instruction syntax rules.
    pub syntax: FormatSyntax,
    /// Per-instruction qualifier rules.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub qualifier: Option<FormatQualifier>,
    /// Per-instruction aliases rules.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub aliases: Option<FormatAliasInstruction<A>>,
    /// Per-instruction encoding rules.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub encodings: Option<E>,
}

impl<A, E> ConfigInstruction<A, E> {
    pub fn new() -> Self {
        Self::default()
    }
}

impl<A, E> Default for ConfigInstruction<A, E> {
    fn default() -> Self {
        Self {
            syntax: FormatSyntax::default(),
            qualifier: None,
            aliases: None,
            encodings: None,
        }
    }
}

/// Trait to retrieve the syntax and qualifier object.
pub trait HasConfigInstruction {
    fn syntax(&self) -> &FormatSyntax;
    fn qualifier(&self) -> &Option<FormatQualifier>;
}

impl<A, E> HasConfigInstruction for ConfigInstruction<A, E> {
    fn syntax(&self) -> &FormatSyntax {
        &self.syntax
    }

    fn qualifier(&self) -> &Option<FormatQualifier> {
        &self.qualifier
    }
}

// -----------------------------------------------------------------------------------------------
// Aliases
// -----------------------------------------------------------------------------------------------

/// Type that represents the global alias settings.
///
/// It specifies Charm's default behavior when using an alias is possible.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatAliasGlobal {
    /// Never use the alias, regardless of any condition.
    Never,
    /// Follows ARM's recommendations.
    #[default]
    Recommended,
    /// Always use the alias, regardless of any condition.
    Always,
}

/// Type that represents the per-instruction alias settings.
///
/// It specifies Charm's behavior for a given encoding when using an alias is possible.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatAliasInstruction<A> {
    /// Never use the alias, regardless of any condition.
    Never,
    /// Follows ARM's recommendations.
    #[default]
    Recommended,
    /// If multiple aliases are possible, try to use this alias first.
    Preferred(A),
    /// Always use the alias, regardless of any condition.
    Always(A),
}

// -----------------------------------------------------------------------------------------------
// Qualifier
// -----------------------------------------------------------------------------------------------

/// Type that represents the encoding width qualifier settings.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatQualifier {
    /// Always display the encoding width qualifier.
    Always,
    /// Only display the qualifier for wide encodings.
    WideOnly,
    /// Follows ARM's recommendations.
    #[default]
    Recommended,
    /// Never display the encoding width qualifier.
    Never,
}

// -----------------------------------------------------------------------------------------------
// Syntax
// -----------------------------------------------------------------------------------------------

/// Type that represent the integer formatting configuration.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatInteger {
    /// Display integers as signed decimal numbers.
    #[default]
    DecimalSigned,
    /// Display integers as unsigned decimal numbers.
    DecimalUnsigned,
    /// Display integers as signed hexdecimal numbers.
    HexadecimalSigned,
    /// Display integers as unsigned hexdecimal numbers.
    HexadecimalUnsigned,
}

/// Type that represent the [`SpecialRegister`](super::operand::SpecialRegister) formatting configuration.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub enum FormatSpecialRegister {
    /// Display special registers in lowercase.
    Lowercase,
    /// Display special registers as they appear in the ARM documentation.
    #[default]
    Recommended,
    /// Display special registers in uppercase.
    Uppercase,
}

/// Type that represents the global syntax settings.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct FormatSyntaxGlobal {
    /// Settings for a register that can be omitted when it is *used* as both the source and the
    /// destination.
    /// For example, in `ADCS{<q>} {<Rdn>, }<Rdn>, <Rm>`, this would control whether or not `<Rdn>`
    /// is displayed.
    pub omit_src_dst_same_reg: bool,
    /// Controls if a register that can be omitted when it *can* be used as both the source and the
    /// destination should be displayed.
    /// For example, `ADC{<c>}{<q>} {<Rd>, }<Rn>, <Rm>, RRX`, this would control whether or not
    /// `<Rd>` is displayed if `<Rd> == <Rn>`.
    pub omit_src_dst_diff_reg: bool,
    /// For example, `RFE{IA}{<c>}{<q>} <Rn>{!}`, this would control whether or not `IA` is
    /// displayed.
    pub omit_address_mode: bool,
    /// Controls how positive numbers are displayed.
    pub positive_integer_format: FormatInteger,
    /// Controls how negative numbers are displayed.
    pub negative_integer_format: FormatInteger,
    /// Controls how special registers are displayed.
    pub special_register_format: FormatSpecialRegister,
}

/// Type that represents the per-instruction syntax settings.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct FormatSyntax {
    /// Settings for a register that can be omitted when it is *used* as both the source and the
    /// destination.
    /// For example, in `ADCS{<q>} {<Rdn>, }<Rdn>, <Rm>`, this would control whether or not `<Rdn>`
    /// is displayed.
    pub omit_src_dst_same_reg: Option<bool>,
    /// Controls if a register that can be omitted when it *can* be used as both the source and the
    /// destination should be displayed.
    /// For example, `ADC{<c>}{<q>} {<Rd>, }<Rn>, <Rm>, RRX`, this would control whether or not
    /// `<Rd>` is displayed if `<Rd> == <Rn>`.
    pub omit_src_dst_diff_reg: Option<bool>,
    /// For example, `RFE{IA}{<c>}{<q>} <Rn>{!}`, this would control whether or not `IA` is
    /// displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub omit_address_mode: Option<bool>,
    /// Controls how positive numbers are displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub positive_integer_format: Option<FormatInteger>,
    /// Controls how negative numbers are displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub negative_integer_format: Option<FormatInteger>,
    /// Controls how special registers are displayed.
    ///
    /// If `None`, defaults to the corresponding global configuration value.
    pub special_register_format: Option<FormatSpecialRegister>,
}

impl FormatSyntax {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn get_omit_src_dst_same_reg(&self, global: &FormatSyntaxGlobal) -> bool {
        if let Some(value) = self.omit_src_dst_same_reg {
            return value;
        }
        global.omit_src_dst_same_reg
    }

    pub fn get_omit_src_dst_diff_reg(&self, global: &FormatSyntaxGlobal) -> bool {
        if let Some(value) = self.omit_src_dst_diff_reg {
            return value;
        }
        global.omit_src_dst_diff_reg
    }

    pub fn get_omit_address_mode(&self, global: &FormatSyntaxGlobal) -> bool {
        if let Some(value) = self.omit_address_mode {
            return value;
        }
        global.omit_address_mode
    }

    pub fn get_positive_integer_format(&self, global: &FormatSyntaxGlobal) -> FormatInteger {
        if let Some(value) = self.positive_integer_format {
            return value;
        }
        global.positive_integer_format
    }

    pub fn get_negative_integer_format(&self, global: &FormatSyntaxGlobal) -> FormatInteger {
        if let Some(value) = self.negative_integer_format {
            return value;
        }
        global.negative_integer_format
    }

    pub fn get_special_register_format(
        &self,
        global: &FormatSyntaxGlobal,
    ) -> FormatSpecialRegister {
        if let Some(value) = self.special_register_format {
            return value;
        }
        global.special_register_format
    }
}

// -----------------------------------------------------------------------------------------------
// LLVM Config
// -----------------------------------------------------------------------------------------------

/// Configuration making Charm behave similarly to LLVM.
pub struct ConfigLLVM {}

impl ConfigLLVM {
    /// Creates a new LLVM configuration.
    pub fn new() -> Config {
        let mut config = Config::default();

        // ---------------------------------------------------------------------------------------
        // Per-instruction - Encodings
        config.instructions.add_i_t4.encodings = Some(AddIT4Encodings::Alt2);
        config.instructions.add_sp_i_t4.encodings = Some(AddSpIT4Encodings::Alt2);
        config.instructions.ldr_l_t2.encodings = Some(LdrLT2Encodings::Alt3);
        config.instructions.ldrb_l_t1.encodings = Some(LdrbLT1Encodings::Alt2);
        config.instructions.ldrh_l_t1.encodings = Some(LdrhLT1Encodings::Alt2);
        config.instructions.ldrsb_l_t1.encodings = Some(LdrsbLT1Encodings::Alt2);
        config.instructions.ldrsh_l_t1.encodings = Some(LdrshLT1Encodings::Alt2);
        config.instructions.mov_i_t3.encodings = Some(MovIT3Encodings::Alt2);
        config.instructions.pld_l_t1.encodings = Some(PldLT1Encodings::Alt2);
        config.instructions.pli_i_t3.encodings = Some(PliIT3Encodings::Alt2);
        config.instructions.rsb_i_t2.encodings = Some(RsbIT2Encodings::Alt1);
        config.instructions.rsbs_i_t2.encodings = Some(RsbsIT2Encodings::Alt1);
        config.instructions.str_i_t4_pre.aliases =
            Some(FormatAliasInstruction::<StrIT4PreAliases>::Never);
        config.instructions.sub_i_t4.encodings = Some(SubIT4Encodings::Alt2);

        // ---------------------------------------------------------------------------------------
        // Per-instruction - Qualifier
        config.instructions.adds_sp_i_t3.qualifier = Some(FormatQualifier::Always);
        config.instructions.cmn_i_t1.qualifier = Some(FormatQualifier::Always);
        config.instructions.cpsid_t2_asm.qualifier = Some(FormatQualifier::Never);
        config.instructions.cpsie_t2_asm.qualifier = Some(FormatQualifier::Never);
        config.instructions.hvc_t1.qualifier = Some(FormatQualifier::Always);
        config.instructions.ldc_i_t1_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldc_i_t1_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldc_i_t1_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldc_i_t1_unind.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldc_l_t1_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldc_l_t1_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldc_l_t1_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldc_l_t1_unind.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldr_i_t4_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldr_i_t4_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldr_i_t4_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrb_i_t3_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrb_i_t3_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrb_i_t3_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrd_i_t1_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrd_i_t1_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrd_i_t1_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrd_l_t1_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrd_l_t1_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrd_l_t1_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrh_i_t3_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrh_i_t3_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrh_i_t3_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrsb_i_t2_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrsb_i_t2_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrsb_i_t2_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrsh_i_t2_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrsh_i_t2_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.ldrsh_i_t2_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.mov_i_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.mov_i_t3.qualifier = Some(FormatQualifier::Never);
        config.instructions.mov_r_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.mov_r_t2.qualifier = Some(FormatQualifier::Never);
        config.instructions.mul_t2.qualifier = Some(FormatQualifier::Never);
        config.instructions.orn_r_t1_rrx.qualifier = Some(FormatQualifier::Never);
        config.instructions.orn_r_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.orns_r_t1_rrx.qualifier = Some(FormatQualifier::Never);
        config.instructions.orns_r_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.pld_i_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.pld_i_t2.qualifier = Some(FormatQualifier::Never);
        config.instructions.pld_l_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.pldw_i_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.pldw_i_t2.qualifier = Some(FormatQualifier::Never);
        config.instructions.pli_i_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.pli_i_t2.qualifier = Some(FormatQualifier::Never);
        config.instructions.pli_i_t3.qualifier = Some(FormatQualifier::Never);
        config.instructions.ror_mov_r_t3.qualifier = Some(FormatQualifier::Always);
        config.instructions.rors_movs_r_t3.qualifier = Some(FormatQualifier::Always);
        config.instructions.rsb_r_t1_rrx.qualifier = Some(FormatQualifier::Never);
        config.instructions.rsb_r_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.rsbs_r_t1_rrx.qualifier = Some(FormatQualifier::Never);
        config.instructions.rsbs_r_t1.qualifier = Some(FormatQualifier::Never);
        config.instructions.ssat_t1_asr.qualifier = Some(FormatQualifier::Never);
        config.instructions.ssat_t1_lsl.qualifier = Some(FormatQualifier::Never);
        config.instructions.stc_t1_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.stc_t1_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.stc_t1_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.stc_t1_unind.qualifier = Some(FormatQualifier::Never);
        config.instructions.str_i_t4_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.str_i_t4_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.str_i_t4_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.strb_i_t3_offn.qualifier = Some(FormatQualifier::Never);
        config.instructions.strb_i_t3_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.strb_i_t3_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.strd_i_t1_off.qualifier = Some(FormatQualifier::Never);
        config.instructions.strd_i_t1_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.strd_i_t1_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.strh_i_t3_offn.qualifier = Some(FormatQualifier::Never);
        config.instructions.strh_i_t3_post.qualifier = Some(FormatQualifier::Never);
        config.instructions.strh_i_t3_pre.qualifier = Some(FormatQualifier::Never);
        config.instructions.sub_i_t4.qualifier = Some(FormatQualifier::Never);
        config.instructions.subs_pc_t5_as.qualifier = Some(FormatQualifier::Never);
        config.instructions.subs_sp_i_t2.qualifier = Some(FormatQualifier::Always);
        config.instructions.teq_i_t1.qualifier = Some(FormatQualifier::Always);
        config.instructions.tst_i_t1.qualifier = Some(FormatQualifier::Always);
        config.instructions.usat_t1_asr.qualifier = Some(FormatQualifier::Never);
        config.instructions.usat_t1_lsl.qualifier = Some(FormatQualifier::Never);

        // ---------------------------------------------------------------------------------------
        // Per-instruction - Aliases
        config.instructions.ldr_i_t4_post.aliases =
            Some(FormatAliasInstruction::<LdrIT4PostAliases>::Never);

        // ---------------------------------------------------------------------------------------
        // Per-instruction - Syntax
        config.instructions.dmb_t1.syntax.positive_integer_format =
            Some(FormatInteger::HexadecimalUnsigned);
        config.instructions.dsb_t1.syntax.positive_integer_format =
            Some(FormatInteger::HexadecimalUnsigned);
        config.instructions.isb_t1.syntax.positive_integer_format =
            Some(FormatInteger::HexadecimalUnsigned);
        config.instructions.ldm_t1.syntax.omit_address_mode = Some(true);
        config.instructions.ldm_t2.syntax.omit_address_mode = Some(true);
        config.instructions.mrs_t1_as.syntax.special_register_format =
            Some(FormatSpecialRegister::Lowercase);
        config.instructions.pop_ldm_t2.syntax.omit_address_mode = Some(true);
        config.instructions.stm_t1.syntax.omit_address_mode = Some(true);
        config.instructions.stm_t2.syntax.omit_address_mode = Some(true);

        // ---------------------------------------------------------------------------------------
        // Global - Syntax
        config.global.syntax.omit_src_dst_diff_reg = false;
        config.global.syntax.omit_src_dst_same_reg = true;

        config
    }
}