msg_tool\scripts\entis_gls\csx\v2/
disasm.rs

1use super::types::*;
2use crate::ext::io::*;
3use crate::types::*;
4use crate::utils::struct_pack::*;
5use anyhow::Result;
6use std::collections::HashMap;
7use std::io::{Seek, Write};
8
9fn escape_string(s: &str) -> String {
10    s.replace("\\", "\\\\")
11        .replace("\r", "\\r")
12        .replace("\n", "\\n")
13        .replace("\t", "\\t")
14}
15
16#[allow(dead_code)]
17pub struct ECSExecutionImageDisassembler<'a> {
18    pub stream: MemReaderRef<'a>,
19    function: &'a SectionFunction,
20    func_info: &'a SectionFuncInfo,
21    import_native_func: &'a SectionImportNativeFunc,
22    class_info: &'a SectionClassInfo,
23    const_string: &'a SectionConstString,
24    pub assembly: ECSExecutionImageAssembly,
25    writer: Option<Box<dyn Write + 'a>>,
26    addr: u32,
27    code: CSInstructionCode,
28    pub func_map: HashMap<u32, &'a FuncInfoEntry>,
29}
30
31impl<'a> ECSExecutionImageDisassembler<'a> {
32    pub fn new(
33        stream: MemReaderRef<'a>,
34        function: &'a SectionFunction,
35        func_info: &'a SectionFuncInfo,
36        import_native_func: &'a SectionImportNativeFunc,
37        class_info: &'a SectionClassInfo,
38        const_string: &'a SectionConstString,
39        writer: Option<Box<dyn Write + 'a>>,
40    ) -> Self {
41        Self {
42            stream,
43            function,
44            func_info,
45            import_native_func,
46            class_info,
47            const_string,
48            assembly: ECSExecutionImageAssembly {
49                commands: Vec::new(),
50            },
51            writer,
52            addr: 0,
53            code: CsicNew,
54            func_map: func_info
55                .functions
56                .iter()
57                .map_while(|x| {
58                    if x.header.bytes == 0 {
59                        None
60                    } else {
61                        Some((x.header.address, x))
62                    }
63                })
64                .collect(),
65        }
66    }
67
68    pub fn execute(&mut self) -> Result<()> {
69        let mut ordered = self.func_info.functions.clone();
70        ordered.sort_by_key(|f| f.header.address);
71        let img_len = self.stream.data.len() as u32;
72        let mut pre_end = 0;
73        for e in ordered {
74            // ignore inline functions
75            if e.header.flags == 0x11 {
76                eprintln!(
77                    "Skipping inline function at {:#x}, {}",
78                    e.header.address, e.name.0
79                );
80                continue;
81            }
82            let start = e.header.address;
83            if e.header.bytes == u32::MAX {
84                // eprintln!("function at {:#x} has invalid size, {}", start, e.name.0);
85                continue;
86            }
87            let end = start + e.header.bytes;
88            if end > img_len {
89                eprintln!(
90                    "Warning: function end {:#x} exceeds image length {:#x}",
91                    end, img_len
92                );
93                crate::COUNTER.inc_warning();
94                continue;
95            }
96            if pre_end != 0 && pre_end < start {
97                self.assembly.push(ECSExecutionImageCommandRecord {
98                    code: CodeSystemReserved,
99                    addr: pre_end,
100                    size: start - pre_end,
101                    new_addr: pre_end,
102                    internal: true,
103                });
104            }
105            self.execute_range(start, end)?;
106            pre_end = end;
107        }
108        if pre_end != 0 && pre_end < img_len {
109            self.assembly.push(ECSExecutionImageCommandRecord {
110                code: CodeSystemReserved,
111                addr: pre_end,
112                size: img_len - pre_end,
113                new_addr: pre_end,
114                internal: true,
115            });
116        }
117        if self.func_info.functions.is_empty() {
118            // older format without function info
119            // try to disassemble the whole section
120            // assuming there are no padding bytes
121            self.execute_range(0, img_len)?;
122        }
123        Ok(())
124    }
125
126    fn line<S: AsRef<str> + ?Sized>(&mut self, line: &S) -> anyhow::Result<()> {
127        if let Some(writer) = &mut self.writer {
128            writeln!(writer, "{:08x} {}", self.addr, line.as_ref())?;
129        }
130        Ok(())
131    }
132
133    fn execute_range(&mut self, start: u32, end: u32) -> Result<()> {
134        self.stream.pos = start as usize;
135        let end = end as usize;
136        // println!("Disassembling range {:#08x} - {:#08x}", start, end);
137        while self.stream.pos < end {
138            self.addr = self.stream.pos as u32;
139            let code = self.stream.read_u8()?;
140            self.code = CSInstructionCode::try_from(code).map_err(|_| {
141                anyhow::anyhow!(
142                    "Invalid CSInstructionCode value: {} at {:08x}",
143                    code,
144                    self.addr
145                )
146            })?;
147            match self.code {
148                CsicNew => self.command_new()?,
149                CsicFree => self.command_free()?,
150                CsicLoad => self.command_load()?,
151                CsicStore => self.command_store()?,
152                CsicEnter => self.command_enter()?,
153                CsicLeave => self.command_leave()?,
154                CsicJump => self.command_jump()?,
155                CsicCJump => self.command_cjump()?,
156                CsicCall => self.command_call()?,
157                CsicReturn => self.command_return()?,
158                CsicElement => self.command_element()?,
159                CsicElementIndirect => self.command_element_indirect()?,
160                CsicOperate => self.command_operate()?,
161                CsicUniOperate => self.command_uni_operate()?,
162                CsicCompare => self.command_compare()?,
163                CsicExOperate => self.command_ex_operate()?,
164                CsicExUniOperate => self.command_ex_uni_operate()?,
165                CsicExCall => self.command_ex_call()?,
166                CsicExReturn => self.command_ex_return()?,
167                CsicCallMember => self.command_call_member()?,
168                CsicCallNativeMember => self.command_call_native_member()?,
169                CsicSwap => self.command_swap()?,
170                CsicCreateBufferVSize => self.command_create_buffer_vsize()?,
171                CsicPointerToObject => self.command_pointer_to_object()?,
172                CsicReferenceForPointer => self.command_reference_for_pointer()?,
173                CsicCallNativeFunction => self.command_call_native_function()?,
174                CodeLoadMem => self.shell_command_load_mem()?,
175                CodeLoadMemBaseImm32 => self.shell_command_load_mem_base_imm32()?,
176                CodeLoadMemBaseIndex => self.shell_command_load_mem_base_index()?,
177                CodeLoadMemBaseIndexImm32 => self.shell_command_load_mem_base_index_imm32()?,
178                CodeStoreMem => self.shell_command_store_mem()?,
179                CodeStoreMemBaseImm32 => self.shell_command_store_mem_base_imm32()?,
180                CodeStoreMemBaseIndex => self.shell_command_store_mem_base_index()?,
181                CodeStoreMemBaseIndexImm32 => self.shell_command_store_mem_base_index_imm32()?,
182                CodeLoadLocal => self.shell_command_load_local()?,
183                CodeLoadLocalIndexImm32 => self.shell_command_load_local_index_imm32()?,
184                CodeStoreLocal => self.shell_command_store_local()?,
185                CodeStoreLocalIndexImm32 => self.shell_command_store_local_index_imm32()?,
186                CodeMoveReg => self.shell_command_move_reg()?,
187                CodeCvtFloat2Int => self.shell_command_cvt_float_2_int()?,
188                CodeCvtInt2Float => self.shell_command_cvt_int_2_float()?,
189                CodeSrlImm8 => self.shell_command_srl_imm8()?,
190                CodeSraImm8 => self.shell_command_sra_imm8()?,
191                CodeSllImm8 => self.shell_command_sll_imm8()?,
192                CodeMaskMove => self.shell_command_mask_move()?,
193                CodeAddImm32 => self.shell_command_add_imm32()?,
194                CodeMulImm32 => self.shell_command_mul_imm32()?,
195                CodeAddSPImm32 => self.shell_command_add_sp_imm32()?,
196                CodeLoadImm64 => self.shell_command_load_imm64()?,
197                CodeNegInt => self.shell_command_neg_int()?,
198                CodeNotInt => self.shell_command_not_int()?,
199                CodeNegFloat => self.shell_command_neg_float()?,
200                CodeAddReg => self.shell_command_add_reg()?,
201                CodeSubReg => self.shell_command_sub_reg()?,
202                CodeMulReg => self.shell_command_mul_reg()?,
203                CodeDivReg => self.shell_command_div_reg()?,
204                CodeModReg => self.shell_command_mod_reg()?,
205                CodeAndReg => self.shell_command_and_reg()?,
206                CodeOrReg => self.shell_command_or_reg()?,
207                CodeXorReg => self.shell_command_xor_reg()?,
208                CodeSrlReg => self.shell_command_srl_reg()?,
209                CodeSraReg => self.shell_command_sra_reg()?,
210                CodeSllReg => self.shell_command_sll_reg()?,
211                CodeMoveSx32Reg => self.shell_command_move_sx32_reg()?,
212                CodeMoveSx16Reg => self.shell_command_move_sx16_reg()?,
213                CodeMoveSx8Reg => self.shell_command_move_sx8_reg()?,
214                CodeFAddReg => self.shell_command_f_add_reg()?,
215                CodeFSubReg => self.shell_command_f_sub_reg()?,
216                CodeFMulReg => self.shell_command_f_mul_reg()?,
217                CodeFDivReg => self.shell_command_f_div_reg()?,
218                CodeMul32Reg => self.shell_command_mul32_reg()?,
219                CodeIMul32Reg => self.shell_command_i_mul32_reg()?,
220                CodeDiv32Reg => self.shell_command_div32_reg()?,
221                CodeIDiv32Reg => self.shell_command_i_div32_reg()?,
222                CodeMod32Reg => self.shell_command_mod32_reg()?,
223                CodeIMod32Reg => self.shell_command_i_mod32_reg()?,
224                CodeCmpNeReg => self.shell_command_cmp_ne_reg()?,
225                CodeCmpEqReg => self.shell_command_cmp_eq_reg()?,
226                CodeCmpLtReg => self.shell_command_cmp_lt_reg()?,
227                CodeCmpLeReg => self.shell_command_cmp_le_reg()?,
228                CodeCmpGtReg => self.shell_command_cmp_gt_reg()?,
229                CodeCmpGeReg => self.shell_command_cmp_ge_reg()?,
230                CodeCmpCReg => self.shell_command_cmp_c_reg()?,
231                CodeCmpCZReg => self.shell_command_cmp_cz_reg()?,
232                CodeFCmpNeReg => self.shell_command_f_cmp_ne_reg()?,
233                CodeFCmpEqReg => self.shell_command_f_cmp_eq_reg()?,
234                CodeFCmpLtReg => self.shell_command_f_cmp_lt_reg()?,
235                CodeFCmpLeReg => self.shell_command_f_cmp_le_reg()?,
236                CodeFCmpGtReg => self.shell_command_f_cmp_gt_reg()?,
237                CodeFCmpGeReg => self.shell_command_f_cmp_ge_reg()?,
238                CodeJumpOffset32 => self.shell_command_jump_offset32()?,
239                CodeJumpReg => self.shell_command_jump_reg()?,
240                CodeCNJumpOffset32 => self.shell_command_cn_jump_offset32()?,
241                CodeCJumpOffset32 => self.shell_command_c_jump_offset32()?,
242                CodeCallImm32 => self.shell_command_call_imm32()?,
243                CodeCallReg => self.shell_command_call_reg()?,
244                CodeSysCallImm32 => self.shell_command_sys_call_imm32()?,
245                CodeSysCallReg => self.shell_command_sys_call_reg()?,
246                CodeReturn => self.shell_command_return()?,
247                CodePushReg => self.shell_command_push_reg()?,
248                CodePopReg => self.shell_command_pop_reg()?,
249                CodePushRegs => self.shell_command_push_regs()?,
250                CodePopRegs => self.shell_command_pop_regs()?,
251                CodeMemoryHint => self.shell_command_memory_hint()?,
252                CodeFloatExtension => self.shell_command_float_extension()?,
253                CodeSIMD64Extension2Op => self.shell_command_simd64_extension_2op()?,
254                CodeSIMD64Extension3Op => self.shell_command_simd64_extension_3op()?,
255                CodeSIMD128Extension2Op => self.shell_command_simd128_extension_2op()?,
256                CodeSIMD128Extension3Op => self.shell_command_simd128_extension_3op()?,
257                CodeEscape => self.shell_command_escape()?,
258                CodeNoOperation => self.shell_command_no_operation()?,
259                CodeSystemReserved => self.shell_command_system_reserved()?,
260            }
261            let size = self.stream.pos as u32 - self.addr;
262            self.assembly.push(ECSExecutionImageCommandRecord {
263                code: self.code,
264                addr: self.addr,
265                size,
266                new_addr: self.addr,
267                internal: false,
268            });
269        }
270        Ok(())
271    }
272
273    fn get_string_literal2(&mut self) -> Result<(Option<usize>, String)> {
274        let length = self.stream.read_u32()?;
275        if length != 0x80000000 {
276            self.stream.seek_relative(-4)?;
277            let s = WideString::unpack(&mut self.stream, false, Encoding::Utf16LE, &None)?.0;
278            Ok((None, s))
279        } else {
280            let index = self.stream.read_u32()? as usize;
281            match self.const_string.strings.get(index) {
282                Some(s) => Ok((Some(index), s.string.0.clone())),
283                None => Err(anyhow::anyhow!(
284                    "Invalid string literal index: {} (max {})",
285                    index,
286                    self.const_string.strings.len()
287                )),
288            }
289        }
290    }
291
292    pub fn get_string_literal(&mut self) -> Result<String> {
293        let (_, s) = self.get_string_literal2()?;
294        Ok(s)
295    }
296
297    fn read_csct(&mut self) -> Result<CSCompareType> {
298        let value = self.stream.read_u8()?;
299        CSCompareType::try_from(value).map_err(|_| {
300            anyhow::anyhow!(
301                "Invalid CSCompareType value: {} at {:08x}",
302                value,
303                self.addr
304            )
305        })
306    }
307
308    pub fn read_csom(&mut self) -> Result<CSObjectMode> {
309        let value = self.stream.read_u8()?;
310        CSObjectMode::try_from(value).map_err(|_| {
311            anyhow::anyhow!("Invalid CSObjectMode value: {} at {:08x}", value, self.addr)
312        })
313    }
314
315    pub fn read_csot(&mut self) -> Result<CSOperatorType> {
316        let value = self.stream.read_u8()?;
317        CSOperatorType::try_from(value).map_err(|_| {
318            anyhow::anyhow!(
319                "Invalid CSOperatorType value: {} at {:08x}",
320                value,
321                self.addr
322            )
323        })
324    }
325
326    fn read_csuot(&mut self) -> Result<CSUnaryOperatorType> {
327        let value = self.stream.read_u8()?;
328        CSUnaryOperatorType::try_from(value).map_err(|_| {
329            anyhow::anyhow!(
330                "Invalid CSUnaryOperatorType value: {} at {:08x}",
331                value,
332                self.addr
333            )
334        })
335    }
336
337    pub fn read_csvt(&mut self) -> Result<CSVariableType> {
338        let value = self.stream.read_u8()?;
339        CSVariableType::try_from(value).map_err(|_| {
340            anyhow::anyhow!(
341                "Invalid CSVariableType value: {} at {:08x}",
342                value,
343                self.addr
344            )
345        })
346    }
347
348    fn read_csxot(&mut self) -> Result<CSExtraOperatorType> {
349        let value = self.stream.read_u8()?;
350        CSExtraOperatorType::try_from(value).map_err(|_| {
351            anyhow::anyhow!(
352                "Invalid CSExtraOperatorType value: {} at {:08x}",
353                value,
354                self.addr
355            )
356        })
357    }
358
359    fn read_csxuot(&mut self) -> Result<CSExtraUniOperatorType> {
360        let value = self.stream.read_u8()?;
361        CSExtraUniOperatorType::try_from(value).map_err(|_| {
362            anyhow::anyhow!(
363                "Invalid CSExtraUniOperatorType value: {} at {:08x}",
364                value,
365                self.addr
366            )
367        })
368    }
369
370    fn command_new(&mut self) -> Result<()> {
371        let csom = self.read_csom()?;
372        let csvt = self.read_csvt()?;
373        let class_name = if csvt == CsvtClassObject {
374            let class_index = self.stream.read_u32()?;
375            match self.class_info.names.get(class_index as usize) {
376                Some(c) => c.0.clone(),
377                None => {
378                    return Err(anyhow::anyhow!(
379                        "Invalid class index: {} (max {}) at {:08x}",
380                        class_index,
381                        self.class_info.names.len(),
382                        self.addr
383                    ));
384                }
385            }
386        } else if csvt == CsvtObject {
387            self.get_string_literal()?
388        } else {
389            String::new()
390        };
391        let var_name = self.get_string_literal()?;
392        let mode = match csom {
393            CsomStack => "stack",
394            CsomThis => "this",
395            _ => {
396                return Err(anyhow::anyhow!(
397                    "Unexpected CSObjectMode in command_new: {:?} at {:08x}",
398                    csom,
399                    self.addr
400                ));
401            }
402        };
403        if class_name.is_empty() {
404            self.line(&format!("New {mode} \"{var_name}\""))?;
405        } else {
406            self.line(&format!("New {mode} \"{class_name}\" \"{var_name}\""))?;
407        }
408        Ok(())
409    }
410
411    fn command_free(&mut self) -> Result<()> {
412        self.line("Free")
413    }
414
415    fn command_load(&mut self) -> Result<()> {
416        let csom = self.read_csom()?;
417        let csvt = self.read_csvt()?;
418        if csom == CsomImmediate {
419            match csvt {
420                CsvtObject => {
421                    let class_name = self.get_string_literal()?;
422                    self.line(&format!("Load New \"{class_name}\""))?;
423                }
424                CsvtReference => {
425                    self.line("Load New \"ECSReference\"")?;
426                }
427                CsvtArray => {
428                    self.line("Load New \"ECSArray\"")?;
429                }
430                CsvtHash => {
431                    self.line("Load New \"ECSHash\"")?;
432                }
433                CsvtInteger => {
434                    let value = self.stream.read_u32()?;
435                    self.line(&format!("Load Integer {value}"))?;
436                }
437                CsvtReal => {
438                    let value = self.stream.read_f64()?;
439                    self.line(&format!("Load Real {value}"))?;
440                }
441                CsvtString => {
442                    let t = self.get_string_literal2()?;
443                    let escaped = escape_string(&t.1);
444                    if let Some(index) = t.0 {
445                        self.line(&format!("Load Const String \"{escaped}\" ({index})"))?;
446                    } else {
447                        self.line(&format!("Load String \"{escaped}\""))?;
448                    }
449                }
450                CsvtInteger64 => {
451                    let value = self.stream.read_u64()?;
452                    self.line(&format!("Load Integer64 {value}"))?;
453                }
454                CsvtPointer => {
455                    let point = self.stream.read_u32()?;
456                    self.line(&format!("Load Pointer {point}"))?;
457                }
458                CsvtClassObject => {
459                    let class_index = self.stream.read_u32()?;
460                    let class_name = match self.class_info.names.get(class_index as usize) {
461                        Some(c) => c.0.clone(),
462                        None => {
463                            return Err(anyhow::anyhow!(
464                                "Invalid class index: {} (max {}) at {:08x}",
465                                class_index,
466                                self.class_info.names.len(),
467                                self.addr
468                            ));
469                        }
470                    };
471                    self.line(&format!("Load New \"{class_name}\""))?;
472                }
473                CsvtBoolean => {
474                    let value = self.stream.read_u8()?;
475                    self.line(&format!("Load Boolean {value}"))?;
476                }
477                _ => {
478                    return Err(anyhow::anyhow!(
479                        "Unexpected variable type in Load Immediate: {:?} at {:08x}",
480                        csvt,
481                        self.addr
482                    ));
483                }
484            }
485        } else {
486            let mode = match csom {
487                CsomStack => "stack",
488                CsomThis => "this",
489                CsomGlobal => "global",
490                CsomData => "data",
491                CsomAuto => "auto",
492                _ => {
493                    return Err(anyhow::anyhow!(
494                        "Unexpected CSObjectMode in command_load: {:?} at {:08x}",
495                        csom,
496                        self.addr
497                    ));
498                }
499            };
500            match csvt {
501                CsvtReference => {
502                    self.line(&format!("Load {mode}"))?;
503                }
504                CsvtInteger => {
505                    let index = self.stream.read_i32()?;
506                    self.line(&format!("Load {mode} [{index}]"))?;
507                }
508                CsvtString => {
509                    let name = self.get_string_literal()?;
510                    self.line(&format!("Load {mode} [\"{name}\"]"))?;
511                }
512                _ => {
513                    return Err(anyhow::anyhow!(
514                        "Unexpected variable type in Load: {:?} at {:08x}",
515                        csvt,
516                        self.addr
517                    ));
518                }
519            }
520        }
521        Ok(())
522    }
523
524    fn command_store(&mut self) -> Result<()> {
525        let csot = self.read_csot()?;
526        match csot {
527            CsotNop => {
528                self.line("Store")?;
529            }
530            CsotAdd => {
531                self.line("Store.Add")?;
532            }
533            CsotSub => {
534                self.line("Store.Sub")?;
535            }
536            CsotMul => {
537                self.line("Store.Mul")?;
538            }
539            CsotDiv => {
540                self.line("Store.Div")?;
541            }
542            CsotMod => {
543                self.line("Store.Mod")?;
544            }
545            CsotAnd => {
546                self.line("Store.And")?;
547            }
548            CsotOr => {
549                self.line("Store.Or")?;
550            }
551            CsotXor => {
552                self.line("Store.Xor")?;
553            }
554            CsotLogicalAnd => {
555                self.line("Store.LAnd")?;
556            }
557            CsotLogicalOr => {
558                self.line("Store.LOr")?;
559            }
560            _ => {
561                return Err(anyhow::anyhow!(
562                    "Unexpected CSOperatorType in command_store: {:?} at {:08x}",
563                    csot,
564                    self.addr
565                ));
566            }
567        }
568        Ok(())
569    }
570
571    fn command_enter(&mut self) -> Result<()> {
572        let name = self.get_string_literal()?;
573        let num_args = self.stream.read_i32()?;
574        if num_args != -1 {
575            let mut sb = String::new();
576            sb.push('(');
577            for i in 0..num_args {
578                let csvt = self.read_csvt()?;
579                let class_name = if csvt == CsvtClassObject {
580                    let class_index = self.stream.read_u32()?;
581                    match self.class_info.names.get(class_index as usize) {
582                        Some(c) => c.0.clone(),
583                        None => {
584                            return Err(anyhow::anyhow!(
585                                "Invalid class index: {} (max {}) at {:08x}",
586                                class_index,
587                                self.class_info.names.len(),
588                                self.addr
589                            ));
590                        }
591                    }
592                } else if csvt == CsvtObject {
593                    self.get_string_literal()?
594                } else {
595                    String::new()
596                };
597                let var_name = self.get_string_literal()?;
598                if class_name.is_empty() {
599                    sb.push_str(&var_name);
600                } else {
601                    sb.push_str(&format!("{{{class_name}:{var_name}}}"));
602                }
603                if i < num_args - 1 {
604                    sb.push_str(", ");
605                }
606            }
607            sb.push(')');
608            self.line(&format!("Enter \"{}\" {}", name, sb))?;
609        } else {
610            let flag = self.stream.read_u8()?;
611            if flag != 0 {
612                return Err(anyhow::anyhow!(
613                    "Invalid flag for variable argument 'enter' instruction: {} at {:08x}",
614                    flag,
615                    self.addr
616                ));
617            }
618            let catch_addr = self.stream.read_i32()? as i64 + self.stream.pos as i64;
619            self.line(&format!("Enter \"{}\" Try-Catch {:08x}", name, catch_addr))?;
620        }
621        Ok(())
622    }
623
624    fn command_leave(&mut self) -> Result<()> {
625        self.line("Leave")
626    }
627
628    fn command_jump(&mut self) -> Result<()> {
629        let addr = self.stream.read_i32()? as i64 + self.stream.pos as i64;
630        self.line(&format!("Jump {addr:08x}"))
631    }
632
633    fn command_cjump(&mut self) -> Result<()> {
634        let cond = self.stream.read_u8()?;
635        let addr = self.stream.read_i32()? as i64 + self.stream.pos as i64;
636        self.line(&format!("CJump {cond} {addr:08x}"))
637    }
638
639    fn command_call(&mut self) -> Result<()> {
640        let csom = self.read_csom()?;
641        let num_args = self.stream.read_i32()?;
642        let func_name = self.get_string_literal()?;
643        let mode = match csom {
644            CsomImmediate if func_name == "@CATCH" => "",
645            CsomThis => "This",
646            CsomGlobal => "Global",
647            CsomAuto => "Auto",
648            _ => {
649                return Err(anyhow::anyhow!(
650                    "Invalid CSObjectMode for 'call' instruction: {:?} {} at {:08x}",
651                    csom,
652                    func_name,
653                    self.addr
654                ));
655            }
656        };
657        self.line(&format!("Call {mode} \"{func_name}\" <{num_args}>"))
658    }
659
660    fn command_return(&mut self) -> Result<()> {
661        let free_stack = self.stream.read_u8()?;
662        if free_stack == 1 {
663            self.line("Return Void")
664        } else {
665            self.line("Return")
666        }
667    }
668
669    fn command_element(&mut self) -> Result<()> {
670        let csvt = self.read_csvt()?;
671        match csvt {
672            CsvtInteger => {
673                let index = self.stream.read_i32()?;
674                self.line(&format!("Element [{index}]"))
675            }
676            CsvtString => {
677                let name = self.get_string_literal()?;
678                self.line(&format!("Element [\"{name}\"]"))
679            }
680            _ => Err(anyhow::anyhow!(
681                "Unexpected variable type in Element: {:?} at {:08x}",
682                csvt,
683                self.addr
684            )),
685        }
686    }
687
688    fn command_element_indirect(&mut self) -> Result<()> {
689        self.line("ElementIndirect")
690    }
691
692    fn command_operate(&mut self) -> Result<()> {
693        let csot = self.read_csot()?;
694        match csot {
695            CsotNop => self.line("Operate.Nop"),
696            CsotAdd => self.line("Operate.Add"),
697            CsotSub => self.line("Operate.Sub"),
698            CsotMul => self.line("Operate.Mul"),
699            CsotDiv => self.line("Operate.Div"),
700            CsotMod => self.line("Operate.Mod"),
701            CsotAnd => self.line("Operate.And"),
702            CsotOr => self.line("Operate.Or"),
703            CsotXor => self.line("Operate.Xor"),
704            CsotLogicalAnd => self.line("Operate.LAnd"),
705            CsotLogicalOr => self.line("Operate.LOr"),
706            CsotShiftRight => self.line("Operate.ShiftRight"),
707            CsotShiftLeft => self.line("Operate.ShiftLeft"),
708        }
709    }
710
711    fn command_uni_operate(&mut self) -> Result<()> {
712        let csuot = self.read_csuot()?;
713        match csuot {
714            CsuotPlus => self.line("UnaryOperate.Plus"),
715            CsuotNegate => self.line("UnaryOperate.Negate"),
716            CsuotBitnot => self.line("UnaryOperate.Bitnot"),
717            CsuotLogicalNot => self.line("UnaryOperate.LogicalNot"),
718        }
719    }
720
721    fn command_compare(&mut self) -> Result<()> {
722        let csct = self.read_csct()?;
723        match csct {
724            CsctEqual => self.line("Compare.Equal"),
725            CsctNotEqual => self.line("Compare.NotEqual"),
726            CsctLessThan => self.line("Compare.LessThan"),
727            CsctLessEqual => self.line("Compare.LessEqual"),
728            CsctGreaterThan => self.line("Compare.GreaterThan"),
729            CsctGreaterEqual => self.line("Compare.GreaterEqual"),
730            CsctNotEqualPointer => self.line("Compare.NotEqualPointer"),
731            CsctEqualPointer => self.line("Compare.EqualPointer"),
732        }
733    }
734
735    fn command_ex_operate(&mut self) -> Result<()> {
736        let csxot = self.read_csxot()?;
737        match csxot {
738            CsxotArrayDim => {
739                let dim = self.stream.read_i32()?;
740                let mut dims = Vec::with_capacity(dim as usize);
741                for _ in 0..dim {
742                    let size = self.stream.read_i32()?;
743                    dims.push(format!("{size}"));
744                }
745                let text = dims.join(", ");
746                self.line(&format!("ExOperate.ArrayDim {{ {text} }}"))
747            }
748            CsxotHashContainer => self.line("ExOperate.HashContainer"),
749            CsxotMoveReference => self.line("ExOperate.MoveReference"),
750        }
751    }
752
753    fn command_ex_uni_operate(&mut self) -> Result<()> {
754        let csxuot = self.read_csxuot()?;
755        match csxuot {
756            CsxuotDeselect => self.line("ExUnaryOperate.Deselect"),
757            CsxuotBoolean => self.line("ExUnaryOperate.Boolean"),
758            CsxuotSizeOf => self.line("ExUnaryOperate.SizeOf"),
759            CsxuotTypeOf => self.line("ExUnaryOperate.TypeOf"),
760            CsxuotStaticCast => {
761                let var_offset = self.stream.read_i32()?;
762                let var_bounds = self.stream.read_i32()?;
763                let func_offset = self.stream.read_i32()?;
764                self.line(&format!(
765                    "ExUnaryOperate.StaticCast {var_offset}, {var_bounds}, {func_offset}"
766                ))
767            }
768            CsxuotDynamicCast => {
769                let cast_type = self.get_string_literal()?;
770                self.line(&format!("ExUnaryOperate.DynamicCast \"{cast_type}\""))
771            }
772            CsxuotDuplicate => self.line("ExUnaryOperate.Duplicate"),
773            CsxuotDelete => self.line("ExUnaryOperate.Delete"),
774            CsxuotDeleteArray => self.line("ExUnaryOperate.DeleteArray"),
775            CsxuotLoadAddress => self.line("ExUnaryOperate.LoadAddress"),
776            CsxuotRefAddress => self.line("ExUnaryOperate.RefAddress"),
777        }
778    }
779
780    fn command_ex_call(&mut self) -> Result<()> {
781        let arg_count = self.stream.read_i32()?;
782        let csom = self.read_csom()?;
783        let csvt = self.read_csvt()?;
784        match csom {
785            CsomImmediate => match csvt {
786                CsvtString => {
787                    let func_name = self.get_string_literal()?;
788                    self.line(&format!("ExCall \"{func_name}\" <{arg_count}>"))
789                }
790                CsvtInteger => {
791                    let func_address = self.stream.read_u32()?;
792                    if let Some(func) = self.func_map.get(&func_address) {
793                        self.line(&format!("ExCall \"{}\" <{arg_count}>", func.name.0))
794                    } else {
795                        self.line(&format!("ExCall {func_address:08x} <{arg_count}>"))
796                    }
797                }
798                _ => {
799                    return Err(anyhow::anyhow!(
800                        "Unexpected CSVariableType in ExCall: {:?} at {:08x}",
801                        csvt,
802                        self.addr
803                    ));
804                }
805            },
806            _ => {
807                return Err(anyhow::anyhow!(
808                    "Unexpected CSObjectMode in ExCall: {:?} at {:08x}",
809                    csom,
810                    self.addr
811                ));
812            }
813        }
814    }
815
816    fn command_ex_return(&mut self) -> Result<()> {
817        let free_stack = self.stream.read_u8()?;
818        if free_stack == 1 {
819            self.line("ExReturn Void")
820        } else {
821            self.line("ExReturn")
822        }
823    }
824
825    fn command_call_member(&mut self) -> Result<()> {
826        let arg_count = self.stream.read_i32()?;
827        let class_index = self.stream.read_u32()?;
828        let class = self
829            .class_info
830            .infos
831            .get(class_index as usize)
832            .ok_or_else(|| {
833                anyhow::anyhow!(
834                    "Invalid class info index: {} (max {}) at {:08x}",
835                    class_index,
836                    self.class_info.infos.len(),
837                    self.addr
838                )
839            })?;
840        let func_index = self.stream.read_u32()?;
841        let func = class.method_info.get(func_index as usize).ok_or_else(|| {
842            anyhow::anyhow!(
843                "Invalid method info index: {} (max {}) at {:08x}",
844                func_index,
845                class.method_info.len(),
846                self.addr
847            )
848        })?;
849        self.line(&format!(
850            "CallMember \"{}\" <{arg_count}>",
851            func.prototype_info.global_name.0
852        ))
853    }
854
855    fn command_call_native_member(&mut self) -> Result<()> {
856        let arg_count = self.stream.read_i32()?;
857        let class_index = self.stream.read_u32()?;
858        let class = self
859            .class_info
860            .infos
861            .get(class_index as usize)
862            .ok_or_else(|| {
863                anyhow::anyhow!(
864                    "Invalid class info index: {} (max {}) at {:08x}",
865                    class_index,
866                    self.class_info.infos.len(),
867                    self.addr
868                )
869            })?;
870        let func_index = self.stream.read_u32()?;
871        let func = class.method_info.get(func_index as usize).ok_or_else(|| {
872            anyhow::anyhow!(
873                "Invalid method info index: {} (max {}) at {:08x}",
874                func_index,
875                class.method_info.len(),
876                self.addr
877            )
878        })?;
879        self.line(&format!(
880            "CallNativeMember \"{}\" <{arg_count}>",
881            func.prototype_info.global_name.0
882        ))
883    }
884
885    fn command_swap(&mut self) -> Result<()> {
886        let _byt_sub_code = self.stream.read_u8()?;
887        let index1 = self.stream.read_i32()?;
888        let index2 = self.stream.read_i32()?;
889        self.line(&format!("Swap #{index1} #{index2}"))
890    }
891
892    fn command_create_buffer_vsize(&mut self) -> Result<()> {
893        self.line("CreateBufferVSize")
894    }
895
896    fn command_pointer_to_object(&mut self) -> Result<()> {
897        let var_type = self.stream.read_i32()?;
898        self.line(&format!("PointerToObject {var_type}"))
899    }
900
901    fn command_reference_for_pointer(&mut self) -> Result<()> {
902        let csvt = self.read_csvt()?;
903        self.line(&format!("ReferenceForPointer {:?}", csvt))
904    }
905
906    fn command_call_native_function(&mut self) -> Result<()> {
907        let arg_count = self.stream.read_i32()?;
908        let func_index = self.stream.read_u32()?;
909        let native_func = self
910            .import_native_func
911            .native_func
912            .names
913            .get(func_index as usize)
914            .ok_or_else(|| {
915                anyhow::anyhow!(
916                    "Invalid native function index: {} (max {}) at {:08x}",
917                    func_index,
918                    self.import_native_func.native_func.names.len(),
919                    self.addr
920                )
921            })?;
922        self.line(&format!(
923            "CallNativeFunction \"{}\" <{arg_count}>",
924            native_func.0
925        ))
926    }
927
928    fn shell_command_load_mem(&mut self) -> Result<()> {
929        let base = self.stream.read_u8()?;
930        let reg = self.stream.read_u8()?;
931        self.line(&format!("LoadMem {base}, %{reg}"))
932    }
933
934    fn shell_command_load_mem_base_imm32(&mut self) -> Result<()> {
935        let base = self.stream.read_u8()?;
936        let reg = self.stream.read_u8()?;
937        let mem = self.stream.read_i32()?;
938        self.line(&format!("LoadMemBaseImm32 %{base}, %{reg}, {mem}"))
939    }
940
941    fn shell_command_load_mem_base_index(&mut self) -> Result<()> {
942        let data_type = self.stream.read_u8()?;
943        let index = self.stream.read_u8()?;
944        let reg = self.stream.read_u8()?;
945        self.line(&format!("LoadMemBaseIndex {data_type}, %{reg}, {index}"))
946    }
947
948    fn shell_command_load_mem_base_index_imm32(&mut self) -> Result<()> {
949        let data_type = self.stream.read_u8()?;
950        let index = self.stream.read_u8()?;
951        let reg = self.stream.read_u8()?;
952        let imm32 = self.stream.read_i32()?;
953        self.line(&format!(
954            "LoadMemBaseIndexImm32 {data_type}, %{reg}, {index}, {imm32}"
955        ))
956    }
957
958    fn shell_command_store_mem(&mut self) -> Result<()> {
959        let data_type = self.stream.read_u8()?;
960        let reg = self.stream.read_u8()?;
961        self.line(&format!("StoreMem {data_type}, %{reg}"))
962    }
963
964    fn shell_command_store_mem_base_imm32(&mut self) -> Result<()> {
965        let base = self.stream.read_u8()?;
966        let reg = self.stream.read_u8()?;
967        let mem = self.stream.read_i32()?;
968        self.line(&format!("StoreMemBaseImm32 %{base}, %{reg}, {mem}"))
969    }
970
971    fn shell_command_store_mem_base_index(&mut self) -> Result<()> {
972        let data_type = self.stream.read_u8()?;
973        let index = self.stream.read_u8()?;
974        let reg = self.stream.read_u8()?;
975        self.line(&format!("StoreMemBaseIndex {data_type}, %{reg}, {index}"))
976    }
977
978    fn shell_command_store_mem_base_index_imm32(&mut self) -> Result<()> {
979        let data_type = self.stream.read_u8()?;
980        let index = self.stream.read_u8()?;
981        let reg = self.stream.read_u8()?;
982        let imm32 = self.stream.read_i32()?;
983        self.line(&format!(
984            "StoreMemBaseIndexImm32 {data_type}, %{reg}, {index}, {imm32}"
985        ))
986    }
987
988    fn shell_command_load_local(&mut self) -> Result<()> {
989        let data_type = self.stream.read_u8()?;
990        let reg = self.stream.read_u8()?;
991        let mem = self.stream.read_i32()?;
992        self.line(&format!("LoadLocal {data_type}, %{reg}, {mem}"))
993    }
994
995    fn shell_command_load_local_index_imm32(&mut self) -> Result<()> {
996        let data_type = self.stream.read_u8()?;
997        let index = self.stream.read_u8()?;
998        let reg = self.stream.read_u8()?;
999        let imm32 = self.stream.read_i32()?;
1000        self.line(&format!(
1001            "LoadLocalIndexImm32 {data_type}, %{reg}, {index}, {imm32}"
1002        ))
1003    }
1004
1005    fn shell_command_store_local(&mut self) -> Result<()> {
1006        let data_type = self.stream.read_u8()?;
1007        let reg = self.stream.read_u8()?;
1008        let mem = self.stream.read_i32()?;
1009        self.line(&format!("StoreLocal {data_type}, %{reg}, {mem}"))
1010    }
1011
1012    fn shell_command_store_local_index_imm32(&mut self) -> Result<()> {
1013        let data_type = self.stream.read_u8()?;
1014        let index = self.stream.read_u8()?;
1015        let reg = self.stream.read_u8()?;
1016        let imm32 = self.stream.read_i32()?;
1017        self.line(&format!(
1018            "StoreLocalIndexImm32 {data_type}, %{reg}, {index}, {imm32}"
1019        ))
1020    }
1021
1022    fn shell_command_move_reg(&mut self) -> Result<()> {
1023        let dst = self.stream.read_u8()?;
1024        let src = self.stream.read_u8()?;
1025        self.line(&format!("MoveReg %{dst}, %{src}"))
1026    }
1027
1028    fn shell_command_cvt_float_2_int(&mut self) -> Result<()> {
1029        let dst = self.stream.read_u8()?;
1030        let src = self.stream.read_u8()?;
1031        self.line(&format!("CvtFloat2Int %{dst}, %{src}"))
1032    }
1033
1034    fn shell_command_cvt_int_2_float(&mut self) -> Result<()> {
1035        let dst = self.stream.read_u8()?;
1036        let src = self.stream.read_u8()?;
1037        self.line(&format!("CvtInt2Float %{dst}, %{src}"))
1038    }
1039
1040    fn shell_command_srl_imm8(&mut self) -> Result<()> {
1041        let dst = self.stream.read_u8()?;
1042        let src = self.stream.read_u8()?;
1043        let imm = self.stream.read_u8()?;
1044        self.line(&format!("SrlImm8 %{dst}, %{src}, {imm}"))
1045    }
1046
1047    fn shell_command_sra_imm8(&mut self) -> Result<()> {
1048        let dst = self.stream.read_u8()?;
1049        let src = self.stream.read_u8()?;
1050        let imm = self.stream.read_u8()?;
1051        self.line(&format!("SraImm8 %{dst}, %{src}, {imm}"))
1052    }
1053
1054    fn shell_command_sll_imm8(&mut self) -> Result<()> {
1055        let dst = self.stream.read_u8()?;
1056        let src = self.stream.read_u8()?;
1057        let imm = self.stream.read_u8()?;
1058        self.line(&format!("SllImm8 %{dst}, %{src}, {imm}"))
1059    }
1060
1061    fn shell_command_mask_move(&mut self) -> Result<()> {
1062        let dst = self.stream.read_u8()?;
1063        let src1 = self.stream.read_u8()?;
1064        let src2 = self.stream.read_u8()?;
1065        self.line(&format!("MaskMove %{dst}, %{src1}, %{src2}"))
1066    }
1067
1068    fn shell_command_add_imm32(&mut self) -> Result<()> {
1069        let dst = self.stream.read_u8()?;
1070        let src = self.stream.read_u8()?;
1071        let imm = self.stream.read_i32()?;
1072        self.line(&format!("AddImm32 %{dst}, %{src}, {imm}"))
1073    }
1074
1075    fn shell_command_mul_imm32(&mut self) -> Result<()> {
1076        let dst = self.stream.read_u8()?;
1077        let src = self.stream.read_u8()?;
1078        let imm = self.stream.read_i32()?;
1079        self.line(&format!("MulImm32 %{dst}, %{src}, {imm}"))
1080    }
1081
1082    fn shell_command_add_sp_imm32(&mut self) -> Result<()> {
1083        let val = self.stream.read_i32()?;
1084        self.line(&format!("AddSPImm32 {val}"))
1085    }
1086
1087    fn shell_command_load_imm64(&mut self) -> Result<()> {
1088        let reg = self.stream.read_u8()?;
1089        let imm = self.stream.read_i64()?;
1090        self.line(&format!("LoadImm64 %{reg}, {imm}"))
1091    }
1092
1093    fn shell_command_neg_int(&mut self) -> Result<()> {
1094        let dst = self.stream.read_u8()?;
1095        self.line(&format!("NegInt %{dst}"))
1096    }
1097
1098    fn shell_command_not_int(&mut self) -> Result<()> {
1099        let dst = self.stream.read_u8()?;
1100        self.line(&format!("NotInt %{dst}"))
1101    }
1102
1103    fn shell_command_neg_float(&mut self) -> Result<()> {
1104        let dst = self.stream.read_u8()?;
1105        self.line(&format!("NegFloat %{dst}"))
1106    }
1107
1108    fn shell_command_add_reg(&mut self) -> Result<()> {
1109        let dst = self.stream.read_u8()?;
1110        let src = self.stream.read_u8()?;
1111        self.line(&format!("AddReg %{dst}, %{src}"))
1112    }
1113
1114    fn shell_command_sub_reg(&mut self) -> Result<()> {
1115        let dst = self.stream.read_u8()?;
1116        let src = self.stream.read_u8()?;
1117        self.line(&format!("SubReg %{dst}, %{src}"))
1118    }
1119
1120    fn shell_command_mul_reg(&mut self) -> Result<()> {
1121        let dst = self.stream.read_u8()?;
1122        let src = self.stream.read_u8()?;
1123        self.line(&format!("MulReg %{dst}, %{src}"))
1124    }
1125
1126    fn shell_command_div_reg(&mut self) -> Result<()> {
1127        let dst = self.stream.read_u8()?;
1128        let src = self.stream.read_u8()?;
1129        self.line(&format!("DivReg %{dst}, %{src}"))
1130    }
1131
1132    fn shell_command_mod_reg(&mut self) -> Result<()> {
1133        let dst = self.stream.read_u8()?;
1134        let src = self.stream.read_u8()?;
1135        self.line(&format!("ModReg %{dst}, %{src}"))
1136    }
1137
1138    fn shell_command_and_reg(&mut self) -> Result<()> {
1139        let dst = self.stream.read_u8()?;
1140        let src = self.stream.read_u8()?;
1141        self.line(&format!("AndReg %{dst}, %{src}"))
1142    }
1143
1144    fn shell_command_or_reg(&mut self) -> Result<()> {
1145        let dst = self.stream.read_u8()?;
1146        let src = self.stream.read_u8()?;
1147        self.line(&format!("OrReg %{dst}, %{src}"))
1148    }
1149
1150    fn shell_command_xor_reg(&mut self) -> Result<()> {
1151        let dst = self.stream.read_u8()?;
1152        let src = self.stream.read_u8()?;
1153        self.line(&format!("XorReg %{dst}, %{src}"))
1154    }
1155
1156    fn shell_command_srl_reg(&mut self) -> Result<()> {
1157        let dst = self.stream.read_u8()?;
1158        let src = self.stream.read_u8()?;
1159        self.line(&format!("SrlReg %{dst}, %{src}"))
1160    }
1161
1162    fn shell_command_sra_reg(&mut self) -> Result<()> {
1163        let dst = self.stream.read_u8()?;
1164        let src = self.stream.read_u8()?;
1165        self.line(&format!("SraReg %{dst}, %{src}"))
1166    }
1167
1168    fn shell_command_sll_reg(&mut self) -> Result<()> {
1169        let dst = self.stream.read_u8()?;
1170        let src = self.stream.read_u8()?;
1171        self.line(&format!("SllReg %{dst}, %{src}"))
1172    }
1173
1174    fn shell_command_move_sx32_reg(&mut self) -> Result<()> {
1175        let dst = self.stream.read_u8()?;
1176        let src = self.stream.read_u8()?;
1177        self.line(&format!("MoveSx32Reg %{dst}, %{src}"))
1178    }
1179
1180    fn shell_command_move_sx16_reg(&mut self) -> Result<()> {
1181        let dst = self.stream.read_u8()?;
1182        let src = self.stream.read_u8()?;
1183        self.line(&format!("MoveSx16Reg %{dst}, %{src}"))
1184    }
1185
1186    fn shell_command_move_sx8_reg(&mut self) -> Result<()> {
1187        let dst = self.stream.read_u8()?;
1188        let src = self.stream.read_u8()?;
1189        self.line(&format!("MoveSx8Reg %{dst}, %{src}"))
1190    }
1191
1192    fn shell_command_f_add_reg(&mut self) -> Result<()> {
1193        let dst = self.stream.read_u8()?;
1194        let src = self.stream.read_u8()?;
1195        self.line(&format!("FAddReg %{dst}, %{src}"))
1196    }
1197
1198    fn shell_command_f_sub_reg(&mut self) -> Result<()> {
1199        let dst = self.stream.read_u8()?;
1200        let src = self.stream.read_u8()?;
1201        self.line(&format!("FSubReg %{dst}, %{src}"))
1202    }
1203
1204    fn shell_command_f_mul_reg(&mut self) -> Result<()> {
1205        let dst = self.stream.read_u8()?;
1206        let src = self.stream.read_u8()?;
1207        self.line(&format!("FMulReg %{dst}, %{src}"))
1208    }
1209
1210    fn shell_command_f_div_reg(&mut self) -> Result<()> {
1211        let dst = self.stream.read_u8()?;
1212        let src = self.stream.read_u8()?;
1213        self.line(&format!("FDivReg %{dst}, %{src}"))
1214    }
1215
1216    fn shell_command_mul32_reg(&mut self) -> Result<()> {
1217        let dst = self.stream.read_u8()?;
1218        let src = self.stream.read_u8()?;
1219        self.line(&format!("Mul32Reg %{dst}, %{src}"))
1220    }
1221
1222    fn shell_command_i_mul32_reg(&mut self) -> Result<()> {
1223        let dst = self.stream.read_u8()?;
1224        let src = self.stream.read_u8()?;
1225        self.line(&format!("IMul32Reg %{dst}, %{src}"))
1226    }
1227
1228    fn shell_command_div32_reg(&mut self) -> Result<()> {
1229        let dst = self.stream.read_u8()?;
1230        let src = self.stream.read_u8()?;
1231        self.line(&format!("Div32Reg %{dst}, %{src}"))
1232    }
1233
1234    fn shell_command_i_div32_reg(&mut self) -> Result<()> {
1235        let dst = self.stream.read_u8()?;
1236        let src = self.stream.read_u8()?;
1237        self.line(&format!("IDiv32Reg %{dst}, %{src}"))
1238    }
1239
1240    fn shell_command_mod32_reg(&mut self) -> Result<()> {
1241        let dst = self.stream.read_u8()?;
1242        let src = self.stream.read_u8()?;
1243        self.line(&format!("Mod32Reg %{dst}, %{src}"))
1244    }
1245
1246    fn shell_command_i_mod32_reg(&mut self) -> Result<()> {
1247        let dst = self.stream.read_u8()?;
1248        let src = self.stream.read_u8()?;
1249        self.line(&format!("IMod32Reg %{dst}, %{src}"))
1250    }
1251
1252    fn shell_command_cmp_ne_reg(&mut self) -> Result<()> {
1253        let dst = self.stream.read_u8()?;
1254        let src = self.stream.read_u8()?;
1255        self.line(&format!("CmpNeReg %{dst}, %{src}"))
1256    }
1257
1258    fn shell_command_cmp_eq_reg(&mut self) -> Result<()> {
1259        let dst = self.stream.read_u8()?;
1260        let src = self.stream.read_u8()?;
1261        self.line(&format!("CmpEqReg %{dst}, %{src}"))
1262    }
1263
1264    fn shell_command_cmp_lt_reg(&mut self) -> Result<()> {
1265        let dst = self.stream.read_u8()?;
1266        let src = self.stream.read_u8()?;
1267        self.line(&format!("CmpLtReg %{dst}, %{src}"))
1268    }
1269
1270    fn shell_command_cmp_le_reg(&mut self) -> Result<()> {
1271        let dst = self.stream.read_u8()?;
1272        let src = self.stream.read_u8()?;
1273        self.line(&format!("CmpLeReg %{dst}, %{src}"))
1274    }
1275
1276    fn shell_command_cmp_gt_reg(&mut self) -> Result<()> {
1277        let dst = self.stream.read_u8()?;
1278        let src = self.stream.read_u8()?;
1279        self.line(&format!("CmpGtReg %{dst}, %{src}"))
1280    }
1281
1282    fn shell_command_cmp_ge_reg(&mut self) -> Result<()> {
1283        let dst = self.stream.read_u8()?;
1284        let src = self.stream.read_u8()?;
1285        self.line(&format!("CmpGeReg %{dst}, %{src}"))
1286    }
1287
1288    fn shell_command_cmp_c_reg(&mut self) -> Result<()> {
1289        let dst = self.stream.read_u8()?;
1290        let src = self.stream.read_u8()?;
1291        self.line(&format!("CmpCReg %{dst}, %{src}"))
1292    }
1293
1294    fn shell_command_cmp_cz_reg(&mut self) -> Result<()> {
1295        let dst = self.stream.read_u8()?;
1296        let src = self.stream.read_u8()?;
1297        self.line(&format!("CmpCZReg %{dst}, %{src}"))
1298    }
1299
1300    fn shell_command_f_cmp_ne_reg(&mut self) -> Result<()> {
1301        let dst = self.stream.read_u8()?;
1302        let src = self.stream.read_u8()?;
1303        self.line(&format!("FCmpNeReg %{dst}, %{src}"))
1304    }
1305
1306    fn shell_command_f_cmp_eq_reg(&mut self) -> Result<()> {
1307        let dst = self.stream.read_u8()?;
1308        let src = self.stream.read_u8()?;
1309        self.line(&format!("FCmpEqReg %{dst}, %{src}"))
1310    }
1311
1312    fn shell_command_f_cmp_lt_reg(&mut self) -> Result<()> {
1313        let dst = self.stream.read_u8()?;
1314        let src = self.stream.read_u8()?;
1315        self.line(&format!("FCmpLtReg %{dst}, %{src}"))
1316    }
1317
1318    fn shell_command_f_cmp_le_reg(&mut self) -> Result<()> {
1319        let dst = self.stream.read_u8()?;
1320        let src = self.stream.read_u8()?;
1321        self.line(&format!("FCmpLeReg %{dst}, %{src}"))
1322    }
1323
1324    fn shell_command_f_cmp_gt_reg(&mut self) -> Result<()> {
1325        let dst = self.stream.read_u8()?;
1326        let src = self.stream.read_u8()?;
1327        self.line(&format!("FCmpGtReg %{dst}, %{src}"))
1328    }
1329
1330    fn shell_command_f_cmp_ge_reg(&mut self) -> Result<()> {
1331        let dst = self.stream.read_u8()?;
1332        let src = self.stream.read_u8()?;
1333        self.line(&format!("FCmpGeReg %{dst}, %{src}"))
1334    }
1335
1336    fn shell_command_jump_offset32(&mut self) -> Result<()> {
1337        let offset = self.stream.read_i32()? as i64;
1338        let dest = self.addr as i64 + offset + 5;
1339        self.line(&format!("JumpOffset32 {dest:08x}"))
1340    }
1341
1342    fn shell_command_jump_reg(&mut self) -> Result<()> {
1343        let reg = self.stream.read_u8()?;
1344        self.line(&format!("JumpReg %{reg}"))
1345    }
1346
1347    fn shell_command_cn_jump_offset32(&mut self) -> Result<()> {
1348        let reg = self.stream.read_u8()?;
1349        let offset = self.stream.read_i32()? as i64;
1350        let dest = self.addr as i64 + offset + 6;
1351        self.line(&format!("CNJumpOffset32 %{reg}, {dest:08x}"))
1352    }
1353
1354    fn shell_command_c_jump_offset32(&mut self) -> Result<()> {
1355        let reg = self.stream.read_u8()?;
1356        let offset = self.stream.read_i32()? as i64;
1357        let dest = self.addr as i64 + offset + 6;
1358        self.line(&format!("CJumpOffset32 %{reg}, {dest:08x}"))
1359    }
1360
1361    fn shell_command_call_imm32(&mut self) -> Result<()> {
1362        let dst = self.stream.read_u32()?;
1363        if let Some(func) = self.func_map.get(&dst) {
1364            self.line(&format!("CallImm32 \"{}\"", func.name.0))
1365        } else {
1366            self.line(&format!("CallImm32 {dst:08x}"))
1367        }
1368    }
1369
1370    fn shell_command_call_reg(&mut self) -> Result<()> {
1371        let reg = self.stream.read_u8()?;
1372        self.line(&format!("CallReg %{reg}"))
1373    }
1374
1375    fn shell_command_sys_call_imm32(&mut self) -> Result<()> {
1376        let num = self.stream.read_i32()?;
1377        self.line(&format!("SysCallImm32 {num:02x}"))
1378    }
1379
1380    fn shell_command_sys_call_reg(&mut self) -> Result<()> {
1381        let reg = self.stream.read_u8()?;
1382        self.line(&format!("SysCallReg %{reg}"))
1383    }
1384
1385    fn shell_command_return(&mut self) -> Result<()> {
1386        self.line("Shell Return")
1387    }
1388
1389    fn shell_command_push_reg(&mut self) -> Result<()> {
1390        let reg = self.stream.read_u8()?;
1391        self.line(&format!("PushReg %{reg}"))
1392    }
1393
1394    fn shell_command_pop_reg(&mut self) -> Result<()> {
1395        let reg = self.stream.read_u8()?;
1396        self.line(&format!("PopReg %{reg}"))
1397    }
1398
1399    fn shell_command_push_regs(&mut self) -> Result<()> {
1400        let reg_first = self.stream.read_u8()?;
1401        let count = self.stream.read_u8()?;
1402        self.line(&format!("PushRegs %{reg_first}, {count}"))
1403    }
1404
1405    fn shell_command_pop_regs(&mut self) -> Result<()> {
1406        let reg_first = self.stream.read_u8()?;
1407        let count = self.stream.read_u8()?;
1408        self.line(&format!("PopRegs %{reg_first}, {count}"))
1409    }
1410
1411    fn shell_command_memory_hint(&mut self) -> Result<()> {
1412        let hint = self.stream.read_u8()?;
1413        let reg = self.stream.read_u8()?;
1414        self.line(&format!("MemoryHint {hint}, %{reg}"))
1415    }
1416
1417    fn shell_command_float_extension(&mut self) -> Result<()> {
1418        let ext = self.stream.read_u8()?;
1419        let reg1 = self.stream.read_u8()?;
1420        let reg2 = self.stream.read_u8()?;
1421        self.line(&format!("FloatExtension {ext}, %{reg1}, %{reg2}"))
1422    }
1423
1424    fn shell_command_simd64_extension_2op(&mut self) -> Result<()> {
1425        let ext = self.stream.read_u8()?;
1426        let reg1 = self.stream.read_u8()?;
1427        let reg2 = self.stream.read_u8()?;
1428        self.line(&format!("SIMD64Extension2Op {ext}, %{reg1}, %{reg2}"))
1429    }
1430
1431    fn shell_command_simd64_extension_3op(&mut self) -> Result<()> {
1432        let ext = self.stream.read_u8()?;
1433        let reg1 = self.stream.read_u8()?;
1434        let reg2 = self.stream.read_u8()?;
1435        let imm = self.stream.read_u8()?;
1436        self.line(&format!(
1437            "SIMD64Extension3Op {ext}, %{reg1}, %{reg2}, {imm}"
1438        ))
1439    }
1440
1441    fn shell_command_simd128_extension_2op(&mut self) -> Result<()> {
1442        let ext = self.stream.read_u8()?;
1443        let dst = self.stream.read_u8()?;
1444        let src = self.stream.read_u8()?;
1445        self.line(&format!("SIMD128Extension2Op {ext}, %{dst}, %{src}"))
1446    }
1447
1448    fn shell_command_simd128_extension_3op(&mut self) -> Result<()> {
1449        let ext = self.stream.read_u8()?;
1450        let dst = self.stream.read_u8()?;
1451        let src = self.stream.read_u8()?;
1452        let imm = self.stream.read_u8()?;
1453        if ext == 0 {
1454            self.line(&format!(
1455                "SIMD128Extension3Op {ext}, %{dst}, %{src}, %{imm}"
1456            ))
1457        } else {
1458            self.line(&format!("SIMD128Extension3Op {ext}, %{dst}, %{src}, {imm}"))
1459        }
1460    }
1461
1462    fn shell_command_escape(&mut self) -> Result<()> {
1463        self.line("Escape")
1464    }
1465
1466    fn shell_command_no_operation(&mut self) -> Result<()> {
1467        self.line("NoOperation")
1468    }
1469
1470    fn shell_command_system_reserved(&mut self) -> Result<()> {
1471        self.line("SystemReserved")
1472    }
1473}