1#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
5mod enums;
6mod enums_shared;
7#[cfg(feature = "fast_fmt")]
8mod fast;
9#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
10mod fmt_consts;
11#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
12mod fmt_opt_provider;
13#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
14mod fmt_opts;
15#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
16mod fmt_utils;
17#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm", feature = "fast_fmt"))]
18mod fmt_utils_all;
19#[cfg(feature = "gas")]
20mod gas;
21#[cfg(feature = "intel")]
22mod intel;
23#[cfg(feature = "masm")]
24mod masm;
25#[cfg(feature = "nasm")]
26mod nasm;
27#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
28mod num_fmt;
29#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
30mod num_fmt_opts;
31#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
32mod pseudo_ops;
33mod regs_tbl;
34#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
35mod regs_tbl_ls;
36#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
37mod string_output;
38mod strings_data;
39#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
40mod strings_tbl;
41mod symres;
42#[cfg(test)]
43pub(crate) mod tests;
44
45#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
46pub use crate::formatter::enums::*;
47pub use crate::formatter::enums_shared::*;
48#[cfg(feature = "fast_fmt")]
49pub use crate::formatter::fast::*;
50#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
51pub use crate::formatter::fmt_opt_provider::*;
52#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
53pub use crate::formatter::fmt_opts::*;
54#[cfg(feature = "gas")]
55pub use crate::formatter::gas::*;
56#[cfg(feature = "intel")]
57pub use crate::formatter::intel::*;
58#[cfg(feature = "masm")]
59pub use crate::formatter::masm::*;
60#[cfg(feature = "nasm")]
61pub use crate::formatter::nasm::*;
62#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
63use crate::formatter::num_fmt::NumberFormatter;
64#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
65pub use crate::formatter::num_fmt_opts::*;
66pub use crate::formatter::symres::*;
67use crate::*;
68use alloc::string::String;
69use alloc::vec::Vec;
70
71#[cfg(any(feature = "gas", feature = "intel", feature = "masm"))]
72#[allow(deprecated)]
73const REGISTER_ST: Register = Register::DontUse0;
74
75#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
76fn r_to_r16(reg: Register) -> Register {
77 if Register::EAX <= reg && reg <= Register::R15 {
78 Register::try_from((((reg as u32 - Register::AX as u32) & 0xF) + Register::AX as u32) as usize).unwrap_or(reg)
79 } else {
80 reg
81 }
82}
83
84#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
85fn r64_to_r32(reg: Register) -> Register {
86 if Register::RAX <= reg && reg <= Register::R15 {
87 Register::try_from((reg as u32 - Register::RAX as u32 + Register::EAX as u32) as usize).unwrap_or(reg)
88 } else {
89 reg
90 }
91}
92
93#[derive(Debug, Default, Clone)]
94#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
95struct FormatterString {
96 lower: String,
97 upper: String,
98}
99
100#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
101impl FormatterString {
102 #[must_use]
103 fn new(lower: String) -> Self {
104 debug_assert_eq!(lower.to_lowercase(), lower);
105 Self { upper: lower.to_uppercase(), lower }
106 }
107
108 #[must_use]
109 fn with_strings(strings: Vec<String>) -> Vec<Self> {
110 strings.into_iter().map(FormatterString::new).collect()
111 }
112
113 #[must_use]
114 fn new_str(lower: &str) -> Self {
115 debug_assert_eq!(lower.to_lowercase(), lower);
116 Self { lower: String::from(lower), upper: lower.to_uppercase() }
117 }
118
119 #[must_use]
120 #[inline]
121 fn len(&self) -> usize {
122 self.lower.len()
123 }
124
125 #[cfg(any(feature = "gas", feature = "intel", feature = "nasm"))]
126 #[must_use]
127 #[inline]
128 fn is_default(&self) -> bool {
129 self.lower.is_empty()
130 }
131
132 #[must_use]
133 #[inline]
134 fn get(&self, upper: bool) -> &str {
135 if upper {
136 &self.upper
137 } else {
138 &self.lower
139 }
140 }
141}
142
143#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
150pub trait FormatterOutput {
151 fn write(&mut self, text: &str, kind: FormatterTextKind);
158
159 #[inline]
167 #[allow(unused_variables)]
168 fn write_prefix(&mut self, instruction: &Instruction, text: &str, prefix: PrefixKind) {
169 self.write(text, FormatterTextKind::Prefix);
170 }
171
172 #[inline]
179 #[allow(unused_variables)]
180 fn write_mnemonic(&mut self, instruction: &Instruction, text: &str) {
181 self.write(text, FormatterTextKind::Mnemonic);
182 }
183
184 #[inline]
196 #[allow(clippy::too_many_arguments)]
197 #[allow(unused_variables)]
198 fn write_number(
199 &mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, text: &str, value: u64, number_kind: NumberKind,
200 kind: FormatterTextKind,
201 ) {
202 self.write(text, kind);
203 }
204
205 #[inline]
215 #[allow(unused_variables)]
216 fn write_decorator(&mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, text: &str, decorator: DecoratorKind) {
217 self.write(text, FormatterTextKind::Decorator);
218 }
219
220 #[inline]
230 #[allow(unused_variables)]
231 fn write_register(&mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, text: &str, register: Register) {
232 self.write(text, FormatterTextKind::Register);
233 }
234
235 #[inline]
245 #[allow(unused_variables)]
246 fn write_symbol(&mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, address: u64, symbol: &SymbolResult<'_>) {
247 match symbol.text {
248 SymResTextInfo::Text(ref part) => {
249 let s = match &part.text {
250 &SymResString::Str(s) => s,
251 SymResString::String(s) => s.as_str(),
252 };
253 self.write(s, part.color);
254 }
255
256 SymResTextInfo::TextVec(v) => {
257 for part in v {
258 let s = match &part.text {
259 &SymResString::Str(s) => s,
260 SymResString::String(s) => s.as_str(),
261 };
262 self.write(s, part.color);
263 }
264 }
265 }
266 }
267}
268
269#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
270struct FormatterOutputMethods;
271#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
272impl FormatterOutputMethods {
273 #[allow(clippy::too_many_arguments)]
274 fn write1(
275 output: &mut dyn FormatterOutput, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, options: &FormatterOptions,
276 number_formatter: &mut NumberFormatter, number_options: &NumberFormattingOptions<'_>, address: u64, symbol: &SymbolResult<'_>,
277 show_symbol_address: bool,
278 ) {
279 FormatterOutputMethods::write2(
280 output,
281 instruction,
282 operand,
283 instruction_operand,
284 options,
285 number_formatter,
286 number_options,
287 address,
288 symbol,
289 show_symbol_address,
290 true,
291 false,
292 );
293 }
294
295 #[allow(clippy::too_many_arguments)]
296 fn write2(
297 output: &mut dyn FormatterOutput, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, options: &FormatterOptions,
298 number_formatter: &mut NumberFormatter, number_options: &NumberFormattingOptions<'_>, address: u64, symbol: &SymbolResult<'_>,
299 show_symbol_address: bool, write_minus_if_signed: bool, spaces_between_op: bool,
300 ) {
301 let mut displ = address.wrapping_sub(symbol.address) as i64;
302 if (symbol.flags & SymbolFlags::SIGNED) != 0 {
303 if write_minus_if_signed {
304 output.write("-", FormatterTextKind::Operator);
305 }
306 displ = displ.wrapping_neg();
307 }
308 output.write_symbol(instruction, operand, instruction_operand, address, symbol);
309 let mut number_kind: NumberKind;
310 if displ != 0 {
311 if spaces_between_op {
312 output.write(" ", FormatterTextKind::Text);
313 }
314 let orig_displ = displ as u64;
315 if displ < 0 {
316 output.write("-", FormatterTextKind::Operator);
317 displ = displ.wrapping_neg();
318 if displ <= i8::MAX as i64 + 1 {
319 number_kind = NumberKind::Int8;
320 } else if displ <= i16::MAX as i64 + 1 {
321 number_kind = NumberKind::Int16;
322 } else if displ <= i32::MAX as i64 + 1 {
323 number_kind = NumberKind::Int32;
324 } else {
325 number_kind = NumberKind::Int64;
326 }
327 } else {
328 output.write("+", FormatterTextKind::Operator);
329 if displ <= i8::MAX as i64 {
330 number_kind = NumberKind::Int8;
331 } else if displ <= i16::MAX as i64 {
332 number_kind = NumberKind::Int16;
333 } else if displ <= i32::MAX as i64 {
334 number_kind = NumberKind::Int32;
335 } else {
336 number_kind = NumberKind::Int64;
337 }
338 }
339 if spaces_between_op {
340 output.write(" ", FormatterTextKind::Text);
341 }
342 let s = number_formatter.format_u64_zeros(options, number_options, displ as u64, false);
343 output.write_number(instruction, operand, instruction_operand, s, orig_displ, number_kind, FormatterTextKind::Number);
344 }
345 if show_symbol_address {
346 output.write(" ", FormatterTextKind::Text);
347 output.write("(", FormatterTextKind::Punctuation);
348 let s = if address <= u16::MAX as u64 {
349 number_kind = NumberKind::UInt16;
350 number_formatter.format_u16_zeros(options, number_options, address as u16, true)
351 } else if address <= u32::MAX as u64 {
352 number_kind = NumberKind::UInt32;
353 number_formatter.format_u32_zeros(options, number_options, address as u32, true)
354 } else {
355 number_kind = NumberKind::UInt64;
356 number_formatter.format_u64_zeros(options, number_options, address, true)
357 };
358 output.write_number(instruction, operand, instruction_operand, s, address, number_kind, FormatterTextKind::Number);
359 output.write(")", FormatterTextKind::Punctuation);
360 }
361 }
362}
363
364#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
368pub trait Formatter: private::Sealed {
369 fn format(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput);
376
377 #[must_use]
379 fn options(&self) -> &FormatterOptions;
380
381 #[must_use]
383 fn options_mut(&mut self) -> &mut FormatterOptions;
384
385 #[inline]
392 fn format_mnemonic(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput) {
393 self.format_mnemonic_options(instruction, output, FormatMnemonicOptions::NONE);
394 }
395
396 fn format_mnemonic_options(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput, options: u32);
406
407 #[must_use]
413 fn operand_count(&mut self, instruction: &Instruction) -> u32;
414
415 #[cfg(feature = "instr_info")]
431 fn op_access(&mut self, instruction: &Instruction, operand: u32) -> Result<Option<OpAccess>, IcedError>;
432
433 fn get_instruction_operand(&mut self, instruction: &Instruction, operand: u32) -> Result<Option<u32>, IcedError>;
446
447 fn get_formatter_operand(&mut self, instruction: &Instruction, instruction_operand: u32) -> Result<Option<u32>, IcedError>;
458
459 fn format_operand(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput, operand: u32) -> Result<(), IcedError>;
474
475 fn format_operand_separator(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput);
482
483 fn format_all_operands(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput);
490
491 #[must_use]
497 fn format_register(&mut self, register: Register) -> &str;
498
499 #[must_use]
505 fn format_i8(&mut self, value: i8) -> &str;
506
507 #[must_use]
513 fn format_i16(&mut self, value: i16) -> &str;
514
515 #[must_use]
521 fn format_i32(&mut self, value: i32) -> &str;
522
523 #[must_use]
529 fn format_i64(&mut self, value: i64) -> &str;
530
531 #[must_use]
537 fn format_u8(&mut self, value: u8) -> &str;
538
539 #[must_use]
545 fn format_u16(&mut self, value: u16) -> &str;
546
547 #[must_use]
553 fn format_u32(&mut self, value: u32) -> &str;
554
555 #[must_use]
561 fn format_u64(&mut self, value: u64) -> &str;
562
563 #[must_use]
570 fn format_i8_options(&mut self, value: i8, number_options: &NumberFormattingOptions<'_>) -> &str;
571
572 #[must_use]
579 fn format_i16_options(&mut self, value: i16, number_options: &NumberFormattingOptions<'_>) -> &str;
580
581 #[must_use]
588 fn format_i32_options(&mut self, value: i32, number_options: &NumberFormattingOptions<'_>) -> &str;
589
590 #[must_use]
597 fn format_i64_options(&mut self, value: i64, number_options: &NumberFormattingOptions<'_>) -> &str;
598
599 #[must_use]
606 fn format_u8_options(&mut self, value: u8, number_options: &NumberFormattingOptions<'_>) -> &str;
607
608 #[must_use]
615 fn format_u16_options(&mut self, value: u16, number_options: &NumberFormattingOptions<'_>) -> &str;
616
617 #[must_use]
624 fn format_u32_options(&mut self, value: u32, number_options: &NumberFormattingOptions<'_>) -> &str;
625
626 #[must_use]
633 fn format_u64_options(&mut self, value: u64, number_options: &NumberFormattingOptions<'_>) -> &str;
634}
635
636#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
637mod private {
638 pub trait Sealed {}
639 #[cfg(feature = "gas")]
640 impl Sealed for crate::GasFormatter {}
641 #[cfg(feature = "intel")]
642 impl Sealed for crate::IntelFormatter {}
643 #[cfg(feature = "masm")]
644 impl Sealed for crate::MasmFormatter {}
645 #[cfg(feature = "nasm")]
646 impl Sealed for crate::NasmFormatter {}
647}
648
649#[allow(clippy::manual_map)] fn to_owned<'a>(sym_res: Option<SymbolResult<'_>>, vec: &'a mut Vec<SymResTextPart<'a>>) -> Option<SymbolResult<'a>> {
651 match sym_res {
652 None => None,
653 Some(sym_res) => Some(sym_res.to_owned(vec)),
654 }
655}
656
657#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
658fn get_mnemonic_cc<'a>(options: &FormatterOptions, cc_index: u32, mnemonics: &'a [FormatterString]) -> &'a FormatterString {
659 use crate::iced_constants::IcedConstants;
660 let index = match cc_index {
661 0 => {
663 debug_assert_eq!(mnemonics.len(), 1);
664 0
665 }
666 1 => {
668 debug_assert_eq!(mnemonics.len(), 1);
669 0
670 }
671 2 => {
673 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_B_ENUM_COUNT);
674 options.cc_b() as usize
675 }
676 3 => {
678 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_AE_ENUM_COUNT);
679 options.cc_ae() as usize
680 }
681 4 => {
683 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_E_ENUM_COUNT);
684 options.cc_e() as usize
685 }
686 5 => {
688 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_NE_ENUM_COUNT);
689 options.cc_ne() as usize
690 }
691 6 => {
693 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_BE_ENUM_COUNT);
694 options.cc_be() as usize
695 }
696 7 => {
698 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_A_ENUM_COUNT);
699 options.cc_a() as usize
700 }
701 8 => {
703 debug_assert_eq!(mnemonics.len(), 1);
704 0
705 }
706 9 => {
708 debug_assert_eq!(mnemonics.len(), 1);
709 0
710 }
711 10 => {
713 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_P_ENUM_COUNT);
714 options.cc_p() as usize
715 }
716 11 => {
718 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_NP_ENUM_COUNT);
719 options.cc_np() as usize
720 }
721 12 => {
723 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_L_ENUM_COUNT);
724 options.cc_l() as usize
725 }
726 13 => {
728 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_GE_ENUM_COUNT);
729 options.cc_ge() as usize
730 }
731 14 => {
733 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_LE_ENUM_COUNT);
734 options.cc_le() as usize
735 }
736 15 => {
738 debug_assert_eq!(mnemonics.len(), IcedConstants::CC_G_ENUM_COUNT);
739 options.cc_g() as usize
740 }
741 _ => unreachable!(),
742 };
743 debug_assert!(index < mnemonics.len());
744 &mnemonics[index]
745}