/* $NetBSD: disasm.c,v 1.16 2024/02/07 04:20:26 msaitoh Exp $ */ /* * Copyright (c) 2018 Ryo Shimizu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: disasm.c,v 1.16 2024/02/07 04:20:26 msaitoh Exp $"); #include #include #include #include #ifndef _KERNEL #include #include #endif #define PRINTF di->di_printf #define PRINTADDR di->di_printaddr #define OPFUNC_DECL(func, a, b, c, d, e, f, g, h) \ func(const disasm_interface_t *di, uint64_t pc, uint32_t insn, \ uint64_t a, uint64_t b, uint64_t c, uint64_t d, \ uint64_t e, uint64_t f, uint64_t g, uint64_t h) #define UNUSED0 arg0 __unused #define UNUSED1 arg1 __unused #define UNUSED2 arg2 __unused #define UNUSED3 arg3 __unused #define UNUSED4 arg4 __unused #define UNUSED5 arg5 __unused #define UNUSED6 arg6 __unused #define UNUSED7 arg7 __unused #define OP0FUNC(func) \ static void \ OPFUNC_DECL(func, \ UNUSED0, UNUSED1, UNUSED2, UNUSED3, \ UNUSED4, UNUSED5, UNUSED6, UNUSED7) #define OP1FUNC(func, a) \ static void \ OPFUNC_DECL(func, a, \ UNUSED1, UNUSED2, UNUSED3, UNUSED4, \ UNUSED5, UNUSED6, UNUSED7) #define OP2FUNC(func, a, b) \ static void \ OPFUNC_DECL(func, a, b, \ UNUSED2, UNUSED3, UNUSED4, UNUSED5, \ UNUSED6, UNUSED7) #define OP3FUNC(func, a, b, c) \ static void \ OPFUNC_DECL(func, a, b, c, \ UNUSED3, UNUSED4, UNUSED5, UNUSED6, \ UNUSED7) #define OP4FUNC(func, a, b, c, d) \ static void \ OPFUNC_DECL(func, a, b, c, d, \ UNUSED4, UNUSED5, UNUSED6, UNUSED7) #define OP5FUNC(func, a, b, c, d, e) \ static void \ OPFUNC_DECL( func, a, b, c, d, e, \ UNUSED5, UNUSED6, UNUSED7) #define OP6FUNC(func, a, b, c, d, e, f) \ static void \ OPFUNC_DECL(func, a, b, c, d, e, f, \ UNUSED6, UNUSED7) #define OP7FUNC(func, a, b, c, d, e, f, g) \ static void \ OPFUNC_DECL(func, a, b, c, d, e, f, g, \ UNUSED7) #define OP8FUNC(func, a, b, c, d, e, f, g, h) \ static void \ OPFUNC_DECL(func, a, b, c, d, e, f, g, h) static const char *z_wxregs[2][32] = { { "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr" }, { "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "xzr" } }; static const char *s_wxregs[2][32] = { { "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp" }, { "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp" } }; #define ZREGNAME(s, n) (z_wxregs[(s) & 1][(n) & 31]) #define SREGNAME(s, n) (s_wxregs[(s) & 1][(n) & 31]) static const char *simdregs[5][32] = { { "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15", "b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23", "b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31" }, { "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15", "h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23", "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31" }, { "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31" }, { "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31" }, { "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23", "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31" } }; #define FREGSZ_B 0 #define FREGSZ_H 1 #define FREGSZ_S 2 #define FREGSZ_D 3 #define FREGSZ_Q 4 #define FREGNAME(s, n) (simdregs[(s)][(n) & 31]) static const char *vecregs[32] = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" }; #define VREGNAME(n) vecregs[(n) & 31] static const char *cregs[16] = { "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11", "C12", "C13", "C14", "C15" }; #define CREGNAME(n) cregs[(n) & 15] static const char *conditioncode[16] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" }; #define CONDNAME(c) conditioncode[(c) & 15] #define IVCONDNAME(c) conditioncode[((c) ^ 1) & 15] static const char *barrierop[16] = { "#0", "oshld", "oshst", "osh", "#4", "nshld", "nshst", "nsh", "#8", "ishld", "ishst", "ish", "#12", "ld", "st", "sy" }; #define BARRIERNAME(op) barrierop[(op) & 15] static const char *prefetchop[32] = { "pldl1keep", "pldl1strm", "pldl2keep", "pldl2strm", "pldl3keep", "pldl3strm", "#6", "#7", "plil1keep", "plil1strm", "plil2keep", "plil2strm", "plil3keep", "plil3strm", "#14", "#15", "pstl1keep", "pstl1strm", "pstl2keep", "pstl2strm", "pstl3keep", "pstl3strm", "#22", "#23", "#24", "#25", "#26", "#27", "#28", "#29", "#30", "#31" }; #define PREFETCHNAME(op) prefetchop[(op) & 31] #define SYSREG_ENC(op0, op1, CRn, CRm, op2) \ (((op0)<<19)|((op1)<<16)|((CRn)<<12)|((CRm)<<8)|((op2)<<5)) struct sysreg_table { uint32_t code; const char *regname; }; /* must be sorted by code */ const struct sysreg_table sysreg_table[] = { /* op0 op1 CRn CRm op2 name */ { SYSREG_ENC(2, 0, 0, 0, 2), "osdtrrx_el1" }, { SYSREG_ENC(2, 0, 0, 0, 4), "dbgbvr0_el1" }, { SYSREG_ENC(2, 0, 0, 0, 5), "dbgbcr0_el1" }, { SYSREG_ENC(2, 0, 0, 0, 6), "dbgwvr0_el1" }, { SYSREG_ENC(2, 0, 0, 0, 7), "dbgwcr0_el1" }, { SYSREG_ENC(2, 0, 0, 1, 4), "dbgbvr1_el1" }, { SYSREG_ENC(2, 0, 0, 1, 5), "dbgbcr1_el1" }, { SYSREG_ENC(2, 0, 0, 1, 6), "dbgwvr1_el1" }, { SYSREG_ENC(2, 0, 0, 1, 7), "dbgwcr1_el1" }, { SYSREG_ENC(2, 0, 0, 2, 0), "mdccint_el1" }, { SYSREG_ENC(2, 0, 0, 2, 2), "mdscr_el1" }, { SYSREG_ENC(2, 0, 0, 2, 4), "dbgbvr2_el1" }, { SYSREG_ENC(2, 0, 0, 2, 5), "dbgbcr2_el1" }, { SYSREG_ENC(2, 0, 0, 2, 6), "dbgwvr2_el1" }, { SYSREG_ENC(2, 0, 0, 2, 7), "dbgwcr2_el1" }, { SYSREG_ENC(2, 0, 0, 3, 2), "osdtrtx_el1" }, { SYSREG_ENC(2, 0, 0, 3, 4), "dbgbvr3_el1" }, { SYSREG_ENC(2, 0, 0, 3, 5), "dbgbcr3_el1" }, { SYSREG_ENC(2, 0, 0, 3, 6), "dbgwvr3_el1" }, { SYSREG_ENC(2, 0, 0, 3, 7), "dbgwcr3_el1" }, { SYSREG_ENC(2, 0, 0, 4, 4), "dbgbvr4_el1" }, { SYSREG_ENC(2, 0, 0, 4, 5), "dbgbcr4_el1" }, { SYSREG_ENC(2, 0, 0, 4, 6), "dbgwvr4_el1" }, { SYSREG_ENC(2, 0, 0, 4, 7), "dbgwcr4_el1" }, { SYSREG_ENC(2, 0, 0, 5, 4), "dbgbvr5_el1" }, { SYSREG_ENC(2, 0, 0, 5, 5), "dbgbcr5_el1" }, { SYSREG_ENC(2, 0, 0, 5, 6), "dbgwvr5_el1" }, { SYSREG_ENC(2, 0, 0, 5, 7), "dbgwcr5_el1" }, { SYSREG_ENC(2, 0, 0, 6, 2), "oseccr_el1" }, { SYSREG_ENC(2, 0, 0, 6, 4), "dbgbvr6_el1" }, { SYSREG_ENC(2, 0, 0, 6, 5), "dbgbcr6_el1" }, { SYSREG_ENC(2, 0, 0, 6, 6), "dbgwvr6_el1" }, { SYSREG_ENC(2, 0, 0, 6, 7), "dbgwcr6_el1" }, { SYSREG_ENC(2, 0, 0, 7, 4), "dbgbvr7_el1" }, { SYSREG_ENC(2, 0, 0, 7, 5), "dbgbcr7_el1" }, { SYSREG_ENC(2, 0, 0, 7, 6), "dbgwvr7_el1" }, { SYSREG_ENC(2, 0, 0, 7, 7), "dbgwcr7_el1" }, { SYSREG_ENC(2, 0, 0, 8, 4), "dbgbvr8_el1" }, { SYSREG_ENC(2, 0, 0, 8, 5), "dbgbcr8_el1" }, { SYSREG_ENC(2, 0, 0, 8, 6), "dbgwvr8_el1" }, { SYSREG_ENC(2, 0, 0, 8, 7), "dbgwcr8_el1" }, { SYSREG_ENC(2, 0, 0, 9, 4), "dbgbvr9_el1" }, { SYSREG_ENC(2, 0, 0, 9, 5), "dbgbcr9_el1" }, { SYSREG_ENC(2, 0, 0, 9, 6), "dbgwvr9_el1" }, { SYSREG_ENC(2, 0, 0, 9, 7), "dbgwcr9_el1" }, { SYSREG_ENC(2, 0, 0, 10, 4), "dbgbvr10_el1" }, { SYSREG_ENC(2, 0, 0, 10, 5), "dbgbcr10_el1" }, { SYSREG_ENC(2, 0, 0, 10, 6), "dbgwvr10_el1" }, { SYSREG_ENC(2, 0, 0, 10, 7), "dbgwcr10_el1" }, { SYSREG_ENC(2, 0, 0, 11, 4), "dbgbvr11_el1" }, { SYSREG_ENC(2, 0, 0, 11, 5), "dbgbcr11_el1" }, { SYSREG_ENC(2, 0, 0, 11, 6), "dbgwvr11_el1" }, { SYSREG_ENC(2, 0, 0, 11, 7), "dbgwcr11_el1" }, { SYSREG_ENC(2, 0, 0, 12, 4), "dbgbvr12_el1" }, { SYSREG_ENC(2, 0, 0, 12, 5), "dbgbcr12_el1" }, { SYSREG_ENC(2, 0, 0, 12, 6), "dbgwvr12_el1" }, { SYSREG_ENC(2, 0, 0, 12, 7), "dbgwcr12_el1" }, { SYSREG_ENC(2, 0, 0, 13, 4), "dbgbvr13_el1" }, { SYSREG_ENC(2, 0, 0, 13, 5), "dbgbcr13_el1" }, { SYSREG_ENC(2, 0, 0, 13, 6), "dbgwvr13_el1" }, { SYSREG_ENC(2, 0, 0, 13, 7), "dbgwcr13_el1" }, { SYSREG_ENC(2, 0, 0, 14, 4), "dbgbvr14_el1" }, { SYSREG_ENC(2, 0, 0, 14, 5), "dbgbcr14_el1" }, { SYSREG_ENC(2, 0, 0, 14, 6), "dbgwvr14_el1" }, { SYSREG_ENC(2, 0, 0, 14, 7), "dbgwcr14_el1" }, { SYSREG_ENC(2, 0, 0, 15, 4), "dbgbvr15_el1" }, { SYSREG_ENC(2, 0, 0, 15, 5), "dbgbcr15_el1" }, { SYSREG_ENC(2, 0, 0, 15, 6), "dbgwvr15_el1" }, { SYSREG_ENC(2, 0, 0, 15, 7), "dbgwcr15_el1" }, { SYSREG_ENC(2, 0, 1, 0, 0), "mdrar_el1" }, { SYSREG_ENC(2, 0, 1, 0, 4), "oslar_el1" }, { SYSREG_ENC(2, 0, 1, 1, 4), "oslsr_el1" }, { SYSREG_ENC(2, 0, 1, 3, 4), "osdlr_el1" }, { SYSREG_ENC(2, 0, 1, 4, 4), "dbgprcr_el1" }, { SYSREG_ENC(2, 0, 7, 8, 6), "dbgclaimset_el1" }, { SYSREG_ENC(2, 0, 7, 9, 6), "dbgclaimclr_el1" }, { SYSREG_ENC(2, 0, 7, 14, 6), "dbgauthstatus_el1" }, { SYSREG_ENC(2, 2, 0, 0, 0), "teecr32_el1" }, { SYSREG_ENC(2, 2, 1, 0, 0), "teehbr32_el1" }, { SYSREG_ENC(2, 3, 0, 1, 0), "mdccsr_el0" }, { SYSREG_ENC(2, 3, 0, 4, 0), "dbgdtr_el0" }, { SYSREG_ENC(2, 3, 0, 5, 0), "dbgdtrrx_el0" }, { SYSREG_ENC(2, 4, 0, 7, 0), "dbgvcr32_el2" }, { SYSREG_ENC(3, 0, 0, 0, 0), "midr_el1" }, { SYSREG_ENC(3, 0, 0, 0, 5), "mpidr_el1" }, { SYSREG_ENC(3, 0, 0, 0, 6), "revidr_el1" }, { SYSREG_ENC(3, 0, 0, 1, 0), "id_pfr0_el1" }, { SYSREG_ENC(3, 0, 0, 1, 1), "id_pfr1_el1" }, { SYSREG_ENC(3, 0, 0, 1, 2), "id_dfr0_el1" }, { SYSREG_ENC(3, 0, 0, 1, 3), "id_afr0_el1" }, { SYSREG_ENC(3, 0, 0, 1, 4), "id_mmfr0_el1" }, { SYSREG_ENC(3, 0, 0, 1, 5), "id_mmfr1_el1" }, { SYSREG_ENC(3, 0, 0, 1, 6), "id_mmfr2_el1" }, { SYSREG_ENC(3, 0, 0, 1, 7), "id_mmfr3_el1" }, { SYSREG_ENC(3, 0, 0, 2, 0), "id_isar0_el1" }, { SYSREG_ENC(3, 0, 0, 2, 1), "id_isar1_el1" }, { SYSREG_ENC(3, 0, 0, 2, 2), "id_isar2_el1" }, { SYSREG_ENC(3, 0, 0, 2, 3), "id_isar3_el1" }, { SYSREG_ENC(3, 0, 0, 2, 4), "id_isar4_el1" }, { SYSREG_ENC(3, 0, 0, 2, 5), "id_isar5_el1" }, { SYSREG_ENC(3, 0, 0, 2, 6), "id_mmfr4_el1" }, { SYSREG_ENC(3, 0, 0, 2, 7), "id_isar6_el1" }, { SYSREG_ENC(3, 0, 0, 3, 0), "mvfr0_el1" }, { SYSREG_ENC(3, 0, 0, 3, 1), "mvfr1_el1" }, { SYSREG_ENC(3, 0, 0, 3, 2), "mvfr2_el1" }, { SYSREG_ENC(3, 0, 0, 3, 4), "id_pfr2_el1" }, { SYSREG_ENC(3, 0, 0, 3, 5), "id_dfr1_el1" }, { SYSREG_ENC(3, 0, 0, 3, 6), "id_mmfr5_el1" }, { SYSREG_ENC(3, 0, 0, 4, 0), "id_aa64pfr0_el1" }, { SYSREG_ENC(3, 0, 0, 4, 1), "id_aa64pfr1_el1" }, { SYSREG_ENC(3, 0, 0, 5, 0), "id_aa64dfr0_el1" }, { SYSREG_ENC(3, 0, 0, 5, 1), "id_aa64dfr1_el1" }, { SYSREG_ENC(3, 0, 0, 5, 4), "id_aa64afr0_el1" }, { SYSREG_ENC(3, 0, 0, 5, 5), "id_aa64afr1_el1" }, { SYSREG_ENC(3, 0, 0, 6, 0), "id_aa64isar0_el1" }, { SYSREG_ENC(3, 0, 0, 6, 1), "id_aa64isar1_el1" }, { SYSREG_ENC(3, 0, 0, 7, 0), "id_aa64mmfr0_el1" }, { SYSREG_ENC(3, 0, 0, 7, 1), "id_aa64mmfr1_el1" }, { SYSREG_ENC(3, 0, 0, 7, 2), "id_aa64mmfr2_el1" }, { SYSREG_ENC(3, 0, 1, 0, 0), "sctlr_el1" }, { SYSREG_ENC(3, 0, 1, 0, 1), "actlr_el1" }, { SYSREG_ENC(3, 0, 1, 0, 2), "cpacr_el1" }, { SYSREG_ENC(3, 0, 1, 0, 5), "rgsr_el1" }, { SYSREG_ENC(3, 0, 1, 0, 6), "gcr_el1" }, { SYSREG_ENC(3, 0, 2, 0, 0), "ttbr0_el1" }, { SYSREG_ENC(3, 0, 2, 0, 1), "ttbr1_el1" }, { SYSREG_ENC(3, 0, 2, 0, 2), "tcr_el1" }, { SYSREG_ENC(3, 0, 2, 1, 0), "apiakeylo_el1" }, { SYSREG_ENC(3, 0, 2, 1, 1), "apiakeyhi_el1" }, { SYSREG_ENC(3, 0, 2, 1, 2), "apibkeylo_el1" }, { SYSREG_ENC(3, 0, 2, 1, 3), "apibkeyhi_el1" }, { SYSREG_ENC(3, 0, 2, 2, 0), "apdakeylo_el1" }, { SYSREG_ENC(3, 0, 2, 2, 1), "apdakeyhi_el1" }, { SYSREG_ENC(3, 0, 2, 2, 2), "apdbkeylo_el1" }, { SYSREG_ENC(3, 0, 2, 2, 3), "apdbkeyhi_el1" }, { SYSREG_ENC(3, 0, 2, 3, 0), "apgakeylo_el1" }, { SYSREG_ENC(3, 0, 2, 3, 1), "apgakeyhi_el1" }, { SYSREG_ENC(3, 0, 4, 0, 0), "spsr_el1" }, { SYSREG_ENC(3, 0, 4, 0, 1), "elr_el1" }, { SYSREG_ENC(3, 0, 4, 1, 0), "sp_el0" }, { SYSREG_ENC(3, 0, 4, 2, 0), "spsel" }, { SYSREG_ENC(3, 0, 4, 2, 2), "currentel" }, { SYSREG_ENC(3, 0, 4, 2, 3), "pan" }, { SYSREG_ENC(3, 0, 4, 2, 4), "uao" }, { SYSREG_ENC(3, 0, 5, 1, 0), "afsr0_el1" }, { SYSREG_ENC(3, 0, 5, 1, 1), "afsr1_el1" }, { SYSREG_ENC(3, 0, 5, 2, 0), "esr_el1" }, { SYSREG_ENC(3, 0, 5, 6, 0), "tfsr_el1" }, { SYSREG_ENC(3, 0, 5, 6, 1), "tfsre0_el1" }, { SYSREG_ENC(3, 0, 6, 0, 0), "far_el1" }, { SYSREG_ENC(3, 0, 7, 4, 0), "par_el1" }, { SYSREG_ENC(3, 0, 9, 14, 1), "pmintenset_el1" }, { SYSREG_ENC(3, 0, 9, 14, 2), "pmintenclr_el1" }, { SYSREG_ENC(3, 0, 10, 2, 0), "mair_el1" }, { SYSREG_ENC(3, 0, 10, 3, 0), "amair_el1" }, { SYSREG_ENC(3, 0, 10, 4, 0), "lorsa_el1" }, { SYSREG_ENC(3, 0, 10, 4, 1), "lorea_el1" }, { SYSREG_ENC(3, 0, 10, 4, 2), "lorn_el1" }, { SYSREG_ENC(3, 0, 10, 4, 3), "lorc_el1" }, { SYSREG_ENC(3, 0, 10, 4, 7), "lorid_el1" }, { SYSREG_ENC(3, 0, 12, 0, 0), "vbar_el1" }, { SYSREG_ENC(3, 0, 12, 0, 1), "rvbar_el1" }, { SYSREG_ENC(3, 0, 12, 0, 2), "rmr_el1" }, { SYSREG_ENC(3, 0, 12, 1, 0), "isr_el1" }, { SYSREG_ENC(3, 0, 13, 0, 1), "contextidr_el1" }, { SYSREG_ENC(3, 0, 13, 0, 4), "tpidr_el1" }, { SYSREG_ENC(3, 0, 13, 0, 7), "scxtnum_el1" }, { SYSREG_ENC(3, 0, 14, 1, 0), "cntkctl_el1" }, { SYSREG_ENC(3, 1, 0, 0, 0), "ccsidr_el1" }, { SYSREG_ENC(3, 1, 0, 0, 1), "clidr_el1" }, { SYSREG_ENC(3, 1, 0, 0, 2), "ccsidr2_el1" }, { SYSREG_ENC(3, 1, 0, 0, 4), "gmid_el1" }, { SYSREG_ENC(3, 1, 0, 0, 7), "aidr_el1" }, { SYSREG_ENC(3, 2, 0, 0, 0), "csselr_el1" }, { SYSREG_ENC(3, 3, 0, 0, 1), "ctr_el0" }, { SYSREG_ENC(3, 3, 0, 0, 7), "dczid_el0" }, { SYSREG_ENC(3, 3, 2, 4, 0), "rndr" }, { SYSREG_ENC(3, 3, 2, 4, 1), "rndrrs" }, { SYSREG_ENC(3, 3, 4, 2, 0), "nzcv" }, { SYSREG_ENC(3, 3, 4, 2, 1), "daif" }, { SYSREG_ENC(3, 3, 4, 2, 5), "dit" }, { SYSREG_ENC(3, 3, 4, 2, 6), "ssbs" }, { SYSREG_ENC(3, 3, 4, 2, 7), "tco" }, { SYSREG_ENC(3, 3, 4, 4, 0), "fpcr" }, { SYSREG_ENC(3, 3, 4, 4, 1), "fpsr" }, { SYSREG_ENC(3, 3, 4, 5, 0), "dspsr_el0" }, { SYSREG_ENC(3, 3, 4, 5, 1), "dlr_el0" }, { SYSREG_ENC(3, 3, 9, 12, 0), "pmcr_el0" }, { SYSREG_ENC(3, 3, 9, 12, 1), "pmcntenset_el0" }, { SYSREG_ENC(3, 3, 9, 12, 2), "pmcntenclr_el0" }, { SYSREG_ENC(3, 3, 9, 12, 3), "pmovsclr_el0" }, { SYSREG_ENC(3, 3, 9, 12, 4), "pmswinc_el0" }, { SYSREG_ENC(3, 3, 9, 12, 5), "pmselr_el0" }, { SYSREG_ENC(3, 3, 9, 12, 6), "pmceid0_el0" }, { SYSREG_ENC(3, 3, 9, 12, 7), "pmceid1_el0" }, { SYSREG_ENC(3, 3, 9, 13, 0), "pmccntr_el0" }, { SYSREG_ENC(3, 3, 9, 13, 1), "pmxevtyper_el0" }, { SYSREG_ENC(3, 3, 9, 13, 2), "pmxevcntr_el0" }, { SYSREG_ENC(3, 3, 9, 14, 0), "pmuserenr_el0" }, { SYSREG_ENC(3, 3, 9, 14, 3), "pmovsset_el0" }, { SYSREG_ENC(3, 3, 13, 0, 2), "tpidr_el0" }, { SYSREG_ENC(3, 3, 13, 0, 3), "tpidrro_el0" }, { SYSREG_ENC(3, 3, 13, 0, 7), "scxtnum_el0" }, { SYSREG_ENC(3, 3, 14, 0, 0), "cntfrq_el0" }, { SYSREG_ENC(3, 3, 14, 0, 1), "cntpct_el0" }, { SYSREG_ENC(3, 3, 14, 0, 2), "cntvct_el0" }, { SYSREG_ENC(3, 3, 14, 2, 0), "cntp_tval_el0" }, { SYSREG_ENC(3, 3, 14, 2, 1), "cntp_ctl_el0" }, { SYSREG_ENC(3, 3, 14, 2, 2), "cntp_cval_el0" }, { SYSREG_ENC(3, 3, 14, 3, 0), "cntv_tval_el0" }, { SYSREG_ENC(3, 3, 14, 3, 1), "cntv_ctl_el0" }, { SYSREG_ENC(3, 3, 14, 3, 2), "cntv_cval_el0" }, { SYSREG_ENC(3, 3, 14, 8, 0), "pmevcntr0_el0" }, { SYSREG_ENC(3, 3, 14, 8, 1), "pmevcntr1_el0" }, { SYSREG_ENC(3, 3, 14, 8, 2), "pmevcntr2_el0" }, { SYSREG_ENC(3, 3, 14, 8, 3), "pmevcntr3_el0" }, { SYSREG_ENC(3, 3, 14, 8, 4), "pmevcntr4_el0" }, { SYSREG_ENC(3, 3, 14, 8, 5), "pmevcntr5_el0" }, { SYSREG_ENC(3, 3, 14, 8, 6), "pmevcntr6_el0" }, { SYSREG_ENC(3, 3, 14, 8, 7), "pmevcntr7_el0" }, { SYSREG_ENC(3, 3, 14, 9, 0), "pmevcntr8_el0" }, { SYSREG_ENC(3, 3, 14, 9, 1), "pmevcntr9_el0" }, { SYSREG_ENC(3, 3, 14, 9, 2), "pmevcntr10_el0" }, { SYSREG_ENC(3, 3, 14, 9, 3), "pmevcntr11_el0" }, { SYSREG_ENC(3, 3, 14, 9, 4), "pmevcntr12_el0" }, { SYSREG_ENC(3, 3, 14, 9, 5), "pmevcntr13_el0" }, { SYSREG_ENC(3, 3, 14, 9, 6), "pmevcntr14_el0" }, { SYSREG_ENC(3, 3, 14, 9, 7), "pmevcntr15_el0" }, { SYSREG_ENC(3, 3, 14, 10, 0), "pmevcntr16_el0" }, { SYSREG_ENC(3, 3, 14, 10, 1), "pmevcntr17_el0" }, { SYSREG_ENC(3, 3, 14, 10, 2), "pmevcntr18_el0" }, { SYSREG_ENC(3, 3, 14, 10, 3), "pmevcntr19_el0" }, { SYSREG_ENC(3, 3, 14, 10, 4), "pmevcntr20_el0" }, { SYSREG_ENC(3, 3, 14, 10, 5), "pmevcntr21_el0" }, { SYSREG_ENC(3, 3, 14, 10, 6), "pmevcntr22_el0" }, { SYSREG_ENC(3, 3, 14, 10, 7), "pmevcntr23_el0" }, { SYSREG_ENC(3, 3, 14, 11, 0), "pmevcntr24_el0" }, { SYSREG_ENC(3, 3, 14, 11, 1), "pmevcntr25_el0" }, { SYSREG_ENC(3, 3, 14, 11, 2), "pmevcntr26_el0" }, { SYSREG_ENC(3, 3, 14, 11, 3), "pmevcntr27_el0" }, { SYSREG_ENC(3, 3, 14, 11, 4), "pmevcntr28_el0" }, { SYSREG_ENC(3, 3, 14, 11, 5), "pmevcntr29_el0" }, { SYSREG_ENC(3, 3, 14, 11, 6), "pmevcntr30_el0" }, { SYSREG_ENC(3, 3, 14, 12, 0), "pmevtyper0_el0" }, { SYSREG_ENC(3, 3, 14, 12, 1), "pmevtyper1_el0" }, { SYSREG_ENC(3, 3, 14, 12, 2), "pmevtyper2_el0" }, { SYSREG_ENC(3, 3, 14, 12, 3), "pmevtyper3_el0" }, { SYSREG_ENC(3, 3, 14, 12, 4), "pmevtyper4_el0" }, { SYSREG_ENC(3, 3, 14, 12, 5), "pmevtyper5_el0" }, { SYSREG_ENC(3, 3, 14, 12, 6), "pmevtyper6_el0" }, { SYSREG_ENC(3, 3, 14, 12, 7), "pmevtyper7_el0" }, { SYSREG_ENC(3, 3, 14, 13, 0), "pmevtyper8_el0" }, { SYSREG_ENC(3, 3, 14, 13, 1), "pmevtyper9_el0" }, { SYSREG_ENC(3, 3, 14, 13, 2), "pmevtyper10_el0" }, { SYSREG_ENC(3, 3, 14, 13, 3), "pmevtyper11_el0" }, { SYSREG_ENC(3, 3, 14, 13, 4), "pmevtyper12_el0" }, { SYSREG_ENC(3, 3, 14, 13, 5), "pmevtyper13_el0" }, { SYSREG_ENC(3, 3, 14, 13, 6), "pmevtyper14_el0" }, { SYSREG_ENC(3, 3, 14, 13, 7), "pmevtyper15_el0" }, { SYSREG_ENC(3, 3, 14, 14, 0), "pmevtyper16_el0" }, { SYSREG_ENC(3, 3, 14, 14, 1), "pmevtyper17_el0" }, { SYSREG_ENC(3, 3, 14, 14, 2), "pmevtyper18_el0" }, { SYSREG_ENC(3, 3, 14, 14, 3), "pmevtyper19_el0" }, { SYSREG_ENC(3, 3, 14, 14, 4), "pmevtyper20_el0" }, { SYSREG_ENC(3, 3, 14, 14, 5), "pmevtyper21_el0" }, { SYSREG_ENC(3, 3, 14, 14, 6), "pmevtyper22_el0" }, { SYSREG_ENC(3, 3, 14, 14, 7), "pmevtyper23_el0" }, { SYSREG_ENC(3, 3, 14, 15, 0), "pmevtyper24_el0" }, { SYSREG_ENC(3, 3, 14, 15, 1), "pmevtyper25_el0" }, { SYSREG_ENC(3, 3, 14, 15, 2), "pmevtyper26_el0" }, { SYSREG_ENC(3, 3, 14, 15, 3), "pmevtyper27_el0" }, { SYSREG_ENC(3, 3, 14, 15, 4), "pmevtyper28_el0" }, { SYSREG_ENC(3, 3, 14, 15, 5), "pmevtyper29_el0" }, { SYSREG_ENC(3, 3, 14, 15, 6), "pmevtyper30_el0" }, { SYSREG_ENC(3, 3, 14, 15, 7), "pmccfiltr_el0" }, { SYSREG_ENC(3, 4, 0, 0, 0), "vpidr_el2" }, { SYSREG_ENC(3, 4, 0, 0, 5), "vmpidr_el2" }, { SYSREG_ENC(3, 4, 1, 0, 0), "sctlr_el2" }, { SYSREG_ENC(3, 4, 1, 0, 1), "actlr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 0), "hcr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 1), "mdcr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 2), "cptr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 3), "hstr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 4), "hfgrtr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 5), "hfgwtr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 6), "hfgitr_el2" }, { SYSREG_ENC(3, 4, 1, 1, 7), "hacr_el2" }, { SYSREG_ENC(3, 4, 2, 0, 0), "ttbr0_el2" }, { SYSREG_ENC(3, 4, 2, 0, 1), "ttbr1_el2" }, { SYSREG_ENC(3, 4, 2, 0, 2), "tcr_el2" }, { SYSREG_ENC(3, 4, 2, 1, 0), "vttbr_el2" }, { SYSREG_ENC(3, 4, 2, 1, 2), "vtcr_el2" }, { SYSREG_ENC(3, 4, 2, 2, 0), "vncr_el2" }, { SYSREG_ENC(3, 4, 2, 6, 0), "vsttbr_el2" }, { SYSREG_ENC(3, 4, 2, 6, 2), "vstcr_el2" }, { SYSREG_ENC(3, 4, 3, 0, 0), "dacr32_el2" }, { SYSREG_ENC(3, 4, 3, 1, 4), "hdfgrtr_el2" }, { SYSREG_ENC(3, 4, 3, 1, 5), "hdfgwtr_el2" }, { SYSREG_ENC(3, 4, 3, 1, 6), "hafgrtr_el2" }, { SYSREG_ENC(3, 4, 4, 0, 0), "spsr_el2" }, { SYSREG_ENC(3, 4, 4, 0, 1), "elr_el2" }, { SYSREG_ENC(3, 4, 4, 1, 0), "sp_el1" }, { SYSREG_ENC(3, 4, 4, 3, 0), "spsr_irq" }, { SYSREG_ENC(3, 4, 4, 3, 1), "spsr_abt" }, { SYSREG_ENC(3, 4, 4, 3, 2), "spsr_und" }, { SYSREG_ENC(3, 4, 4, 3, 3), "spsr_fiq" }, { SYSREG_ENC(3, 4, 5, 0, 1), "ifsr32_el2" }, { SYSREG_ENC(3, 4, 5, 1, 0), "afsr0_el2" }, { SYSREG_ENC(3, 4, 5, 1, 1), "afsr1_el2" }, { SYSREG_ENC(3, 4, 5, 2, 0), "esr_el2" }, { SYSREG_ENC(3, 4, 5, 3, 0), "fpexc32_el2" }, { SYSREG_ENC(3, 4, 5, 6, 0), "tfsr_el2" }, { SYSREG_ENC(3, 4, 6, 0, 0), "far_el2" }, { SYSREG_ENC(3, 4, 6, 0, 4), "hpfar_el2" }, { SYSREG_ENC(3, 4, 10, 2, 0), "mair_el2" }, { SYSREG_ENC(3, 4, 10, 3, 0), "amair_el2" }, { SYSREG_ENC(3, 4, 12, 0, 0), "vbar_el2" }, { SYSREG_ENC(3, 4, 12, 0, 1), "rvbar_el2" }, { SYSREG_ENC(3, 4, 12, 0, 2), "rmr_el2" }, { SYSREG_ENC(3, 4, 13, 0, 1), "contextidr_el2" }, { SYSREG_ENC(3, 4, 13, 0, 2), "tpidr_el2" }, { SYSREG_ENC(3, 4, 13, 0, 7), "scxtnum_el2" }, { SYSREG_ENC(3, 4, 14, 0, 3), "cntvoff_el2" }, { SYSREG_ENC(3, 4, 14, 1, 0), "cnthctl_el2" }, { SYSREG_ENC(3, 4, 14, 2, 0), "cnthp_tval_el2" }, { SYSREG_ENC(3, 4, 14, 2, 1), "cnthp_ctl_el2" }, { SYSREG_ENC(3, 4, 14, 2, 2), "cnthp_cval_el2" }, { SYSREG_ENC(3, 4, 14, 3, 0), "cnthv_tval_el2" }, { SYSREG_ENC(3, 4, 14, 3, 1), "cnthv_ctl_el2" }, { SYSREG_ENC(3, 4, 14, 3, 2), "cnthv_cval_el2" }, { SYSREG_ENC(3, 4, 14, 4, 0), "cnthvs_tval_el2" }, { SYSREG_ENC(3, 4, 14, 4, 1), "cnthvs_ctl_el2" }, { SYSREG_ENC(3, 4, 14, 4, 2), "cnthvs_cval_el2" }, { SYSREG_ENC(3, 4, 14, 5, 0), "cnthps_tval_el2" }, { SYSREG_ENC(3, 4, 14, 5, 1), "cnthps_ctl_el2" }, { SYSREG_ENC(3, 4, 14, 5, 2), "cnthps_cval_el2" }, { SYSREG_ENC(3, 6, 1, 0, 0), "sctlr_el3" }, { SYSREG_ENC(3, 6, 1, 0, 1), "actlr_el3" }, { SYSREG_ENC(3, 6, 1, 1, 0), "scr_el3" }, { SYSREG_ENC(3, 6, 1, 1, 1), "sder32_el3" }, { SYSREG_ENC(3, 6, 1, 1, 2), "cptr_el3" }, { SYSREG_ENC(3, 6, 1, 3, 1), "mdcr_el3" }, { SYSREG_ENC(3, 6, 2, 0, 0), "ttbr0_el3" }, { SYSREG_ENC(3, 6, 2, 0, 2), "tcr_el3" }, { SYSREG_ENC(3, 6, 4, 0, 0), "spsr_el3" }, { SYSREG_ENC(3, 6, 4, 0, 1), "elr_el3" }, { SYSREG_ENC(3, 6, 4, 1, 0), "sp_el2" }, { SYSREG_ENC(3, 6, 5, 1, 0), "afsr0_el3" }, { SYSREG_ENC(3, 6, 5, 1, 1), "afsr1_el3" }, { SYSREG_ENC(3, 6, 5, 2, 0), "esr_el3" }, { SYSREG_ENC(3, 6, 5, 6, 0), "tfsr_el3" }, { SYSREG_ENC(3, 6, 6, 0, 0), "far_el3" }, { SYSREG_ENC(3, 6, 10, 2, 0), "mair_el3" }, { SYSREG_ENC(3, 6, 10, 3, 0), "amair_el3" }, { SYSREG_ENC(3, 6, 12, 0, 0), "vbar_el3" }, { SYSREG_ENC(3, 6, 12, 0, 1), "rvbar_el3" }, { SYSREG_ENC(3, 6, 12, 0, 2), "rmr_el3" }, { SYSREG_ENC(3, 6, 13, 0, 2), "tpidr_el3" }, { SYSREG_ENC(3, 6, 13, 0, 7), "scxtnum_el3" }, { SYSREG_ENC(3, 7, 14, 2, 0), "cntps_tval_el1" }, { SYSREG_ENC(3, 7, 14, 2, 1), "cntps_ctl_el1" }, { SYSREG_ENC(3, 7, 14, 2, 2), "cntps_cval_el1" } }; static const char * sysregname_bsearch(uint32_t code) { const struct sysreg_table *base, *p; unsigned int lim; int32_t cmp; base = sysreg_table; for (lim = __arraycount(sysreg_table); lim != 0; lim >>= 1) { p = base + (lim >> 1); cmp = code - p->code; if (cmp == 0) return p->regname; if (cmp > 0) { base = p + 1; lim--; } } return NULL; } #define SYSREG_OP_READ 0x01 #define SYSREG_OP_WRITE 0x02 static const char * sysregname(char *buf, size_t buflen, uint32_t rw, uint64_t op0, uint64_t op1, uint64_t CRn, uint64_t CRm, uint64_t op2) { const char *name; uint32_t code; code = SYSREG_ENC(op0, op1, CRn, CRm, op2); /* special case for dbgdtrrx_el0(RO) and dbgdtrtx_el0(WO) */ if (code == SYSREG_ENC(2,3,0,5,0)) { if (rw & SYSREG_OP_WRITE) return "dbgdtrtx_el0"; return "dbgdtrrx_el0"; } name = sysregname_bsearch(code); if (name == NULL) { #define SYSREGNAMEBUFLEN sizeof("s99_99_c99_c99_99") snprintf(buf, buflen, "s%u_%u_c%u_c%u_%u", (u_int)op0, (u_int)op1, (u_int)CRn, (u_int)CRm, (u_int)op2); return buf; } return name; } #define RSYSREGNAME(buf, buflen, op0, op1, CRn, CRm, op2) \ sysregname(buf, buflen, SYSREG_OP_READ, op0, op1, CRn, CRm, op2) #define WSYSREGNAME(buf, buflen, op0, op1, CRn, CRm, op2) \ sysregname(buf, buflen, SYSREG_OP_WRITE, op0, op1, CRn, CRm, op2) static uint64_t SignExtend(int bitwidth, uint64_t imm, unsigned int multiply) { const uint64_t signbit = ((uint64_t)1 << (bitwidth - 1)); const uint64_t immmax = signbit << 1; if (imm & signbit) imm -= immmax; return imm * multiply; } static uint64_t ZeroExtend(int bitwidth, uint64_t imm, unsigned int multiply) { return imm * multiply; } /* rotate right. if n < 0, rotate left. */ static uint64_t rotate(int bitwidth, uint64_t v, int n) { uint64_t result; n &= (bitwidth - 1); result = (((v << (bitwidth - n)) | (v >> n))); if (bitwidth < 64) result &= ((1ULL << bitwidth) - 1); return result; } static bool ValidBitMasks(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr) { int esize, len; if ((sf == 0) && (n != 0)) return false; len = fls64((n << 6) + (~imms & 0x3f)) - 1; if (len < 0) return false; esize = (1 << len); imms &= (esize - 1); if (imms == (uint64_t)(esize - 1)) return false; return true; } static uint64_t DecodeBitMasks(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr) { const int bitwidth = (sf == 0) ? 32 : 64; uint64_t result; int esize, len; len = fls64((n << 6) + (~imms & 0x3f)) - 1; esize = (1 << len); imms &= (esize - 1); immr &= (esize - 1); result = rotate(esize, (1ULL << (imms + 1)) - 1, immr); while (esize < bitwidth) { result |= (result << esize); esize <<= 1; } if (sf == 0) result &= ((1ULL << bitwidth) - 1); return result; } static bool MoveWidePreferred(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr) { #if 1 uint64_t x = DecodeBitMasks(sf, n, imms, immr); if (sf == 0) x &= 0xffffffff; if (((x & 0xffffffffffff0000UL) == 0) || ((x & 0xffffffff0000ffffUL) == 0) || ((x & 0xffff0000ffffffffUL) == 0) || ((x & 0x0000ffffffffffffUL) == 0)) return true; x = ~x; if (sf == 0) x &= 0xffffffff; if (((x & 0xffffffffffff0000UL) == 0) || ((x & 0xffffffff0000ffffUL) == 0) || ((x & 0xffff0000ffffffffUL) == 0) || ((x & 0x0000ffffffffffffUL) == 0)) return true; return false; #else const int bitwidth = (sf == 0) ? 32 : 64; if ((sf != 0) && (n == 0)) return false; if ((sf == 0) && ((n != 0) || (immr > 0x1f))) return false; if (imms < 16) return ((-immr & 15) <= (15 - imms)); if (imms >= (uint64_t)(bitwidth - 15)) return ((immr & 15) <= (imms - (bitwidth - 15))); return false; #endif } static bool BFXPreferred(uint64_t sf, uint64_t opc, uint64_t imms, uint64_t immr) { const uint64_t bitwidth = (sf == 0) ? 32 : 64; if (imms < immr) return false; if (imms == (bitwidth - 1)) return false; if (immr == 0) { if ((sf == 0) && ((imms == 7) || (imms == 15))) return false; if ((sf != 0) && (opc == 0) && ((imms == 7) || (imms == 15) || (imms == 31))) return false; } return true; } #define SHIFTOP2(s, op1, op2) \ ((const char *[]){ op1, op2 })[(s) & 1] #define SHIFTOP4(s, op1, op2, op3, op4) \ ((const char *[]){ op1, op2, op3, op4 })[(s) & 3] #define SHIFTOP8(s, op1, op2, op3, op4, op5, op6, op7, op8) \ ((const char *[]){ op1, op2, op3, op4, op5, op6, op7, op8 })[(s) & 7] static const char * DecodeShift(uint64_t shift) { return SHIFTOP4(shift, "lsl", "lsr", "asr", "ror"); } #ifdef DISASM_WITH_COMMENT #define UNDEFINED(pc, insn, comment) \ PRINTF(".insn\t0x%08x\t# %s\n", insn, comment); #else #define UNDEFINED(pc, insn, comment) \ PRINTF(".insn\t0x%08x\n", insn); #endif static void extendreg_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t sf, uint64_t Rm, uint64_t option, uint64_t imm3, uint64_t Rn, uint64_t Rd, const char *op, const char *z_op) { const int r = (sf == 0) ? 0 : ((option & 3) == 3) ? 1 : 0; if ((z_op != NULL) && (Rd == 31)) { PRINTF("%s\t", z_op); } else { PRINTF("%s\t%s, ", op, SREGNAME(sf, Rd)); } PRINTF("%s, %s", SREGNAME(sf, Rn), ZREGNAME(r, Rm)); if ((Rd == 31) || (Rn == 31)) { if (imm3 == 0) { if (!((sf == 0) && (option == 2)) && !((sf != 0) && (option == 3))) { PRINTF(", %s", SHIFTOP8(option, "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx")); } } else { PRINTF(", %s #%u", SHIFTOP8(option, "uxtb", "uxth", "lsl", "lsl", "sxtb", "sxth", "sxtw", "sxtx"), (u_int)imm3); } } else { PRINTF(", %s", SHIFTOP8(option, "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx")); if (imm3 != 0) PRINTF(" #%u", (u_int)imm3); } PRINTF("\n"); } static void shiftreg_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t sf, uint64_t shift, uint64_t Rm, uint64_t imm6, uint64_t Rn, uint64_t Rd, const char *dnm_op, const char *dzm_op, const char *znm_op) { if ((sf == 0) && (imm6 >= 32)) { UNDEFINED(pc, insn, "illegal imm6"); return; } if ((dzm_op != NULL) && (Rn == 31)) { PRINTF("%s\t%s, %s", dzm_op, ZREGNAME(sf, Rd), ZREGNAME(sf, Rm)); } else if ((znm_op != NULL) && (Rd == 31)) { PRINTF("%s\t%s, %s", znm_op, ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } else { PRINTF("%s\t%s, %s, %s", dnm_op, ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } if (imm6 != 0) PRINTF(", %s #%u", DecodeShift(shift), (u_int)imm6); PRINTF("\n"); } static inline int regoffset_option_to_r(uint64_t option) { switch (option) { case 2: case 6: return 0; case 3: case 7: return 1; default: return -1; } } static void regoffset_b_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt, const char *op) { int r; if ((r = regoffset_option_to_r(option)) < 0) { UNDEFINED(pc, insn, "illegal option"); return; } if (shift == 0) { PRINTF("%s\t%s, [%s,%s%s]\n", op, ZREGNAME(0, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx")); } else { PRINTF("%s\t%s, [%s,%s,%s #%d]\n", op, ZREGNAME(0, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"), 0); } } static void regoffset_h_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt, uint64_t RtSz, const char *op) { int r; if ((r = regoffset_option_to_r(option)) < 0) { UNDEFINED(pc, insn, "illegal option"); return; } if ((shift == 0) && (option == 3)) { PRINTF("%s\t%s, [%s,%s]\n", op, ZREGNAME(RtSz, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm)); } else if (shift == 0) { PRINTF("%s\t%s, [%s,%s,%s]\n", op, ZREGNAME(RtSz, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx")); } else { PRINTF("%s\t%s, [%s,%s,%s #%u]\n", op, ZREGNAME(RtSz, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"), (u_int)shift); } } static void regoffset_w_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt, const char *op) { int r; if ((r = regoffset_option_to_r(option)) < 0) { UNDEFINED(pc, insn, "illegal option"); return; } if ((shift == 0) && (option == 3)) { PRINTF("%s\t%s, [%s,%s]\n", op, ZREGNAME(1, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm)); } else if (shift == 0) { PRINTF("%s\t%s, [%s,%s,%s]\n", op, ZREGNAME(1, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx")); } else { PRINTF("%s\t%s, [%s,%s,%s #%u]\n", op, ZREGNAME(1, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"), (u_int)shift * 2); } } static void regoffset_x_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t size, uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt, const char *op) { int r; if ((r = regoffset_option_to_r(option)) < 0) { UNDEFINED(pc, insn, "illegal option"); return; } if (shift == 0) { PRINTF("%s\t%s, [%s,%s%s]\n", op, ZREGNAME(size, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx")); } else { uint64_t amount = 2 + size; PRINTF("%s\t%s, [%s,%s,%s #%u]\n", op, ZREGNAME(size, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"), (u_int)amount); } } static void addsub_imm_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t sf, uint64_t shift, uint64_t imm12, uint64_t Rn, uint64_t Rd, const char *op, const char *zop) { if (shift & 2) { UNDEFINED(pc, insn, "illegal shift"); return; } if (Rd == 31) { PRINTF("%s\t%s, #0x%"PRIx64"%s\n", zop, SREGNAME(sf, Rn), ZeroExtend(12, imm12, 1), SHIFTOP4(shift, "", ", lsl #12", "", "")); } else { PRINTF("%s\t%s, %s, #0x%"PRIx64"%s\n", op, ZREGNAME(sf, Rd), SREGNAME(sf, Rn), ZeroExtend(12, imm12, 1), SHIFTOP4(shift, "", ", lsl #12", "", "")); } } static void csetsel_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t sf, uint64_t Rm, uint64_t cond, uint64_t Rn, uint64_t Rd, const char *op, const char *op2, const char *op3) { if ((Rn == Rm) && (Rn != 31) && ((cond & 0xe) != 0x0e)) { PRINTF("%s\t%s, %s, %s\n", op3, ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), IVCONDNAME(cond)); } else if ((Rn == Rm) && (Rn == 31) && ((cond & 0xe) != 0x0e)) { PRINTF("%s\t%s, %s\n", op2, ZREGNAME(sf, Rd), IVCONDNAME(cond)); } else { PRINTF("%s\t%s, %s, %s, %s\n", op, ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), CONDNAME(cond)); } } OP0FUNC(op_undefined) { UNDEFINED(pc, insn, "undefined"); } OP4FUNC(op_adc, sf, Rm, Rn, Rd) { PRINTF("adc\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } OP4FUNC(op_adcs, sf, Rm, Rn, Rd) { PRINTF("adcs\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } OP6FUNC(op_add_extreg, sf, Rm, option, imm3, Rn, Rd) { extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd, "add", NULL); } OP5FUNC(op_add_imm, sf, shift, imm12, Rn, Rd) { if (shift & 2) { UNDEFINED(pc, insn, "illegal shift"); return; } /* ALIAS: mov_tofromsp */ if ((Rd == 31 || Rn == 31) && (imm12 == 0)) { PRINTF("mov\t%s, %s\n", SREGNAME(sf, Rd), SREGNAME(sf, Rn)); } else { PRINTF("add\t%s, %s, #0x%"PRIx64"%s\n", SREGNAME(sf, Rd), SREGNAME(sf, Rn), ZeroExtend(12, imm12, 1), SHIFTOP2(shift, "", ", lsl #12")); } } OP6FUNC(op_add_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { if (shift == 3) { UNDEFINED(pc, insn, "illegal shift"); return; } shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "add", NULL, NULL); } OP6FUNC(op_adds_extreg, sf, Rm, option, imm3, Rn, Rd) { /* ALIAS: cmn_extreg */ extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd, "adds", "cmn"); } OP5FUNC(op_adds_imm, sf, shift, imm12, Rn, Rd) { /* ALIAS: cmn_imm */ addsub_imm_common(di, pc, insn, sf, shift, imm12, Rn, Rd, "adds", "cmn"); } OP6FUNC(op_adds_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { if (shift == 3) { UNDEFINED(pc, insn, "illegal shift"); return; } /* ALIAS: cmn_shiftreg */ shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "adds", NULL, "cmn"); } OP3FUNC(op_adr, immlo, immhi, Rd) { uint64_t imm = ((immhi << 2) | immlo); PRINTF("adr\t%s, ", ZREGNAME(1, Rd)); PRINTADDR(SignExtend(21, imm, 1) + pc); PRINTF("\n"); } OP3FUNC(op_adrp, immlo, immhi, Rd) { uint64_t imm = ((immhi << 2) | immlo); PRINTF("adrp\t%s, ", ZREGNAME(1, Rd)); PRINTADDR(SignExtend(21, imm, 4096) + (pc & -4096)); PRINTF("\n"); } OP6FUNC(op_and_imm, sf, n, immr, imms, Rn, Rd) { if (!ValidBitMasks(sf, n, imms, immr)) { UNDEFINED(pc, insn, "illegal bitmasks"); return; } PRINTF("and\t%s, %s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), DecodeBitMasks(sf, n, imms, immr)); } OP6FUNC(op_and_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "and", NULL, NULL); } OP6FUNC(op_ands_imm, sf, n, immr, imms, Rn, Rd) { if (!ValidBitMasks(sf, n, imms, immr)) { UNDEFINED(pc, insn, "illegal bitmasks"); return; } /* ALIAS: tst_imm */ if (Rd == 31) { PRINTF("tst\t%s, #0x%"PRIx64"\n", ZREGNAME(sf, Rn), DecodeBitMasks(sf, n, imms, immr)); } else { PRINTF("ands\t%s, %s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), DecodeBitMasks(sf, n, imms, immr)); } } OP6FUNC(op_ands_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { /* ALIAS: tst_shiftreg */ shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "ands", NULL, "tst"); } OP6FUNC(op_sbfm, sf, n, immr, imms, Rn, Rd) { const uint64_t bitwidth = (sf == 0) ? 32 : 64; /* ALIAS: asr_imm,sbfiz,sbfx,sxtb,sxth,sxtw */ if ((imms != (bitwidth - 1)) && ((imms + 1) == immr)) { PRINTF("asr\t%s, %s, #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), bitwidth - immr); } else if (imms == (bitwidth - 1)) { PRINTF("asr\t%s, %s, #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), immr); } else if (imms < immr) { PRINTF("sbfiz\t%s, %s, #%"PRIu64", #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), (bitwidth - immr) & (bitwidth - 1), (imms + 1) & (bitwidth - 1)); } else if (BFXPreferred(sf, 0, imms, immr)) { PRINTF("sbfx\t%s, %s, #%"PRIu64", #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), immr, (imms - immr + 1) & (bitwidth - 1)); } else if ((immr == 0) && (imms == 7)) { PRINTF("sxtb\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(0, Rn)); } else if ((immr == 0) && (imms == 15)) { PRINTF("sxth\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(0, Rn)); } else if ((immr == 0) && (imms == 31)) { PRINTF("sxtw\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(0, Rn)); } else { UNDEFINED(pc, insn, "undefined"); } } OP4FUNC(op_asr_reg, sf, Rm, Rn, Rd) { /* ALIAS: asrv */ /* "asr" always the preferred disassembly */ PRINTF("asr\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } struct op_sys_table { uint32_t code; int flags; #define OPE_NONE 0x00000000 #define OPE_XT 0x00000001 const char *opname; }; static struct op_sys_table op_sys_table[] = { { SYSREG_ENC(1, 0, 7, 1, 0), OPE_NONE, "ic\tialluis" }, { SYSREG_ENC(1, 0, 7, 5, 0), OPE_NONE, "ic\tiallu" }, { SYSREG_ENC(1, 3, 7, 5, 1), OPE_XT, "ic\tivau" }, { SYSREG_ENC(1, 0, 7, 6, 1), OPE_XT, "dc\tivac" }, { SYSREG_ENC(1, 0, 7, 6, 2), OPE_XT, "dc\tisw" }, { SYSREG_ENC(1, 0, 7, 10, 2), OPE_XT, "dc\tcsw" }, { SYSREG_ENC(1, 0, 7, 14, 2), OPE_XT, "dc\tcisw" }, { SYSREG_ENC(1, 3, 7, 10, 1), OPE_XT, "dc\tcvac" }, { SYSREG_ENC(1, 3, 7, 11, 1), OPE_XT, "dc\tcvau" }, { SYSREG_ENC(1, 3, 7, 14, 1), OPE_XT, "dc\tcivac" }, { SYSREG_ENC(1, 3, 7, 4, 1), OPE_XT, "dc\tzva" }, { SYSREG_ENC(1, 0, 7, 6, 3), OPE_XT, "dc\tigvac" }, { SYSREG_ENC(1, 0, 7, 6, 4), OPE_XT, "dc\tigsw" }, { SYSREG_ENC(1, 0, 7, 6, 5), OPE_XT, "dc\tigdvac" }, { SYSREG_ENC(1, 0, 7, 6, 6), OPE_XT, "dc\tigdsw" }, { SYSREG_ENC(1, 0, 7, 10, 4), OPE_XT, "dc\tcgsw" }, { SYSREG_ENC(1, 0, 7, 10, 6), OPE_XT, "dc\tcgdsw" }, { SYSREG_ENC(1, 0, 7, 14, 4), OPE_XT, "dc\tcigsw" }, { SYSREG_ENC(1, 0, 7, 14, 6), OPE_XT, "dc\tcigdsw" }, { SYSREG_ENC(1, 3, 7, 4, 3), OPE_XT, "dc\tgva" }, { SYSREG_ENC(1, 3, 7, 4, 4), OPE_XT, "dc\tgzva" }, { SYSREG_ENC(1, 3, 7, 10, 3), OPE_XT, "dc\tcgvac" }, { SYSREG_ENC(1, 3, 7, 10, 5), OPE_XT, "dc\tcgdvac" }, { SYSREG_ENC(1, 3, 7, 12, 3), OPE_XT, "dc\tcgvap" }, { SYSREG_ENC(1, 3, 7, 12, 5), OPE_XT, "dc\tcgdvap" }, { SYSREG_ENC(1, 3, 7, 13, 3), OPE_XT, "dc\tcgvadp" }, { SYSREG_ENC(1, 3, 7, 13, 5), OPE_XT, "dc\tcgdvadp" }, { SYSREG_ENC(1, 3, 7, 14, 3), OPE_XT, "dc\tcigvac" }, { SYSREG_ENC(1, 3, 7, 14, 5), OPE_XT, "dc\tcigdvac" }, { SYSREG_ENC(1, 3, 7, 12, 1), OPE_XT, "dc\tcvap" }, { SYSREG_ENC(1, 3, 7, 13, 1), OPE_XT, "dc\tcvadp" }, { SYSREG_ENC(1, 0, 7, 8, 0), OPE_XT, "at\ts1e1r" }, { SYSREG_ENC(1, 0, 7, 8, 1), OPE_XT, "at\ts1e1w" }, { SYSREG_ENC(1, 0, 7, 8, 2), OPE_XT, "at\ts1e0r" }, { SYSREG_ENC(1, 0, 7, 8, 3), OPE_XT, "at\ts1e0w" }, { SYSREG_ENC(1, 0, 7, 9, 0), OPE_XT, "at\ts1e1rp" }, { SYSREG_ENC(1, 0, 7, 9, 1), OPE_XT, "at\ts1e1wp" }, { SYSREG_ENC(1, 4, 7, 8, 0), OPE_XT, "at\ts1e2r" }, { SYSREG_ENC(1, 4, 7, 8, 1), OPE_XT, "at\ts1e2w" }, { SYSREG_ENC(1, 4, 7, 8, 4), OPE_XT, "at\ts12e1r" }, { SYSREG_ENC(1, 4, 7, 8, 5), OPE_XT, "at\ts12e1w" }, { SYSREG_ENC(1, 4, 7, 8, 6), OPE_XT, "at\ts12e0r" }, { SYSREG_ENC(1, 4, 7, 8, 7), OPE_XT, "at\ts12e0w" }, { SYSREG_ENC(1, 6, 7, 8, 0), OPE_XT, "at\ts1e3r" }, { SYSREG_ENC(1, 6, 7, 8, 1), OPE_XT, "at\ts1e3w" }, { SYSREG_ENC(1, 3, 7, 3, 4), OPE_XT, "cfp\trctx" }, { SYSREG_ENC(1, 3, 7, 3, 5), OPE_XT, "dvp\trctx" }, { SYSREG_ENC(1, 3, 7, 3, 7), OPE_XT, "cpp\trctx" }, { SYSREG_ENC(1, 0, 8, 3, 0), OPE_NONE, "tlbi\tvmalle1is" }, { SYSREG_ENC(1, 0, 8, 3, 1), OPE_XT, "tlbi\tvae1is" }, { SYSREG_ENC(1, 0, 8, 3, 2), OPE_XT, "tlbi\taside1is" }, { SYSREG_ENC(1, 0, 8, 3, 3), OPE_XT, "tlbi\tvaae1is" }, { SYSREG_ENC(1, 0, 8, 3, 5), OPE_XT, "tlbi\tvale1is" }, { SYSREG_ENC(1, 0, 8, 3, 7), OPE_XT, "tlbi\tvaale1is" }, { SYSREG_ENC(1, 0, 8, 7, 0), OPE_NONE, "tlbi\tvmalle1" }, { SYSREG_ENC(1, 0, 8, 7, 1), OPE_XT, "tlbi\tvae1" }, { SYSREG_ENC(1, 0, 8, 7, 2), OPE_XT, "tlbi\taside1" }, { SYSREG_ENC(1, 0, 8, 7, 3), OPE_XT, "tlbi\tvaae1" }, { SYSREG_ENC(1, 0, 8, 7, 5), OPE_XT, "tlbi\tvale1" }, { SYSREG_ENC(1, 0, 8, 7, 7), OPE_XT, "tlbi\tvaale1" }, { SYSREG_ENC(1, 4, 8, 0, 1), OPE_XT, "tlbi\tipas2e1is" }, { SYSREG_ENC(1, 4, 8, 0, 5), OPE_XT, "tlbi\tipas2le1is" }, { SYSREG_ENC(1, 4, 8, 3, 0), OPE_NONE, "tlbi\talle2is" }, { SYSREG_ENC(1, 4, 8, 3, 1), OPE_XT, "tlbi\tvae2is" }, { SYSREG_ENC(1, 4, 8, 3, 4), OPE_NONE, "tlbi\talle1is" }, { SYSREG_ENC(1, 4, 8, 3, 5), OPE_XT, "tlbi\tvale2is" }, { SYSREG_ENC(1, 4, 8, 3, 6), OPE_NONE, "tlbi\tvmalls12e1is" }, { SYSREG_ENC(1, 4, 8, 4, 1), OPE_XT, "tlbi\tipas2e1" }, { SYSREG_ENC(1, 4, 8, 4, 5), OPE_XT, "tlbi\tipas2le1" }, { SYSREG_ENC(1, 4, 8, 7, 0), OPE_NONE, "tlbi\talle2" }, { SYSREG_ENC(1, 4, 8, 7, 1), OPE_XT, "tlbi\tvae2" }, { SYSREG_ENC(1, 4, 8, 7, 4), OPE_NONE, "tlbi\talle1" }, { SYSREG_ENC(1, 4, 8, 7, 5), OPE_XT, "tlbi\tvale2" }, { SYSREG_ENC(1, 4, 8, 7, 6), OPE_NONE, "tlbi\tvmalls12e1" }, { SYSREG_ENC(1, 6, 8, 3, 0), OPE_NONE, "tlbi\talle3is" }, { SYSREG_ENC(1, 6, 8, 3, 1), OPE_XT, "tlbi\tvae3is" }, { SYSREG_ENC(1, 6, 8, 3, 5), OPE_XT, "tlbi\tvale3is" }, { SYSREG_ENC(1, 6, 8, 7, 0), OPE_NONE, "tlbi\talle3" }, { SYSREG_ENC(1, 6, 8, 7, 1), OPE_XT, "tlbi\tvae3" }, { SYSREG_ENC(1, 6, 8, 7, 5), OPE_XT, "tlbi\tvale3" } }; OP5FUNC(op_sys, op1, CRn, CRm, op2, Rt) { uint32_t code; size_t i; /* ALIAS: at,dc,ic,sys,tlbi */ code = SYSREG_ENC(1, op1, CRn, CRm, op2); for (i = 0; i < __arraycount(op_sys_table); i++) { if (op_sys_table[i].code != code) continue; if (((op_sys_table[i].flags & OPE_XT) != 0) || (Rt != 31)) { PRINTF("%s, %s\n", op_sys_table[i].opname, ZREGNAME(1, Rt)); } else { PRINTF("%s\n", op_sys_table[i].opname); } return; } /* default, sys instruction */ PRINTF("sys\t#%"PRIu64", %s, %s, #%"PRIu64", %s\n", op1, CREGNAME(CRn), CREGNAME(CRm), op2, ZREGNAME(1,Rt)); } OP1FUNC(op_b, imm26) { PRINTF("b\t"); PRINTADDR(SignExtend(26, imm26, 4) + pc); PRINTF("\n"); } OP2FUNC(op_b_cond, imm19, cond) { PRINTF("b.%s\t", CONDNAME(cond)); PRINTADDR(SignExtend(19, imm19, 4) + pc); PRINTF("\n"); } OP6FUNC(op_bfi, sf, n, immr, imms, Rn, Rd) { const uint64_t bitwidth = (sf == 0) ? 32 : 64; /* ALIAS: bfm,bfxil */ /* it is not disassembled as bfm */ /* XXX: if Rn=31, should be used "bfc"? (armv8.2) */ if (imms < immr) { PRINTF("bfi\t%s, %s, #%"PRIu64", #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), (bitwidth - immr) & (bitwidth - 1), (imms + 1) & (bitwidth - 1)); } else { PRINTF("bfxil\t%s, %s, #%"PRIu64", #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), immr, (imms -immr + 1) & (bitwidth - 1)); } } OP6FUNC(op_bic_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "bic", NULL, NULL); } OP6FUNC(op_bics_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "bics", NULL, NULL); } OP1FUNC(op_bl, imm26) { PRINTF("bl\t"); PRINTADDR(SignExtend(26, imm26, 4) + pc); PRINTF("\n"); } OP1FUNC(op_blr, Rn) { PRINTF("blr\t%s\n", ZREGNAME(1, Rn)); } OP1FUNC(op_br, Rn) { PRINTF("br\t%s\n", ZREGNAME(1, Rn)); } OP1FUNC(op_brk, imm16) { PRINTF("brk\t#0x%"PRIx64"\n", imm16); } OP3FUNC(op_cbnz, sf, imm19, Rt) { PRINTF("cbnz\t%s, ", ZREGNAME(sf, Rt)); PRINTADDR(SignExtend(19, imm19, 4) + pc); PRINTF("\n"); } OP3FUNC(op_cbz, sf, imm19, Rt) { PRINTF("cbz\t%s, ", ZREGNAME(sf, Rt)); PRINTADDR(SignExtend(19, imm19, 4) + pc); PRINTF("\n"); } OP5FUNC(op_ccmn_imm, sf, imm5, cond, Rn, nzcv) { PRINTF("ccmn\t%s, #0x%"PRIx64", #0x%"PRIx64", %s\n", ZREGNAME(sf, Rn), imm5, nzcv, CONDNAME(cond)); } OP5FUNC(op_ccmn_reg, sf, Rm, cond, Rn, nzcv) { PRINTF("ccmn\t%s, %s, #0x%"PRIx64", %s\n", ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), nzcv, CONDNAME(cond)); } OP5FUNC(op_ccmp_imm, sf, imm5, cond, Rn, nzcv) { PRINTF("ccmp\t%s, #0x%"PRIx64", #0x%"PRIx64", %s\n", ZREGNAME(sf, Rn), imm5, nzcv, CONDNAME(cond)); } OP5FUNC(op_ccmp_reg, sf, Rm, cond, Rn, nzcv) { PRINTF("ccmp\t%s, %s, #0x%"PRIx64", %s\n", ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), nzcv, CONDNAME(cond)); } OP5FUNC(op_cinc, sf, Rm, cond, Rn, Rd) { /* ALIAS: cset,csinc */ csetsel_common(di, pc, insn, sf, Rm, cond, Rn, Rd, "csinc", "cset", "cinc"); } OP5FUNC(op_csinv, sf, Rm, cond, Rn, Rd) { /* ALIAS: csetm,cinv */ csetsel_common(di, pc, insn, sf, Rm, cond, Rn, Rd, "csinv", "csetm", "cinv"); } OP1FUNC(op_clrex, CRm) { if (CRm == 15) { PRINTF("clrex\n"); } else { PRINTF("clrex\t#0x%"PRIx64"\n", CRm); } } OP3FUNC(op_cls, sf, Rn, Rd) { PRINTF("cls\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn)); } OP3FUNC(op_clz, sf, Rn, Rd) { PRINTF("clz\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn)); } OP6FUNC(op_subs_extreg, sf, Rm, option, imm3, Rn, Rd) { /* ALIAS: cmp_extreg */ extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd, "subs", "cmp"); } OP5FUNC(op_subs_imm, sf, shift, imm12, Rn, Rd) { /* ALIAS: cmp_imm */ addsub_imm_common(di, pc, insn, sf, shift, imm12, Rn, Rd, "subs", "cmp"); } OP6FUNC(op_subs_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { if (shift == 3) { UNDEFINED(pc, insn, "illegal shift"); return; } /* ALIAS: negs,cmp_shiftreg */ shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "subs", "negs", "cmp"); } OP5FUNC(op_csneg, sf, Rm, cond, Rn, Rd) { /* ALIAS: cneg */ if ((Rn == Rm) && ((cond & 0xe) != 0x0e)) { PRINTF("cneg\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), IVCONDNAME(cond)); } else { PRINTF("csneg\t%s, %s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), CONDNAME(cond)); } } static void crc32_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn, uint64_t sf, uint64_t Rm, uint64_t sz, uint64_t Rn, uint64_t Rd, const char *op) { const char bhwx[4] = "bhwx"; /* "crc32x" + SizeChar */ if (((sf != 0) && (sz != 3)) || ((sf == 0) && (sz == 3))) { UNDEFINED(pc, insn, "illegal size"); return; } PRINTF("%s%c\t%s, %s, %s\n", op, bhwx[sz & 3], ZREGNAME(0, Rd), ZREGNAME(0, Rn), ZREGNAME(sf, Rm)); } OP5FUNC(op_crc32, sf, Rm, sz, Rn, Rd) { crc32_common(di, pc, insn, sf, Rm, sz, Rn, Rd, "crc32"); } OP5FUNC(op_crc32c, sf, Rm, sz, Rn, Rd) { crc32_common(di, pc, insn, sf, Rm, sz, Rn, Rd, "crc32c"); } OP5FUNC(op_csel, sf, Rm, cond, Rn, Rd) { PRINTF("csel\t%s, %s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), CONDNAME(cond)); } OP2FUNC(op_dcps, imm16, ll) { if (ll == 0) { UNDEFINED(pc, insn, "illegal level"); return; } if (imm16 == 0) PRINTF("dcps%"PRIu64"\n", ll); else PRINTF("dcps%"PRIu64"\t#0x%"PRIx64"\n", ll, imm16); } OP0FUNC(op_drps) { PRINTF("drps\n"); } OP1FUNC(op_dmb, CRm) { PRINTF("dmb\t%s\n", BARRIERNAME(CRm)); } OP1FUNC(op_dsb, CRm) { PRINTF("dsb\t%s\n", BARRIERNAME(CRm)); } OP6FUNC(op_eon_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "eon", NULL, NULL); } OP6FUNC(op_eor_imm, sf, n, immr, imms, Rn, Rd) { if (!ValidBitMasks(sf, n, imms, immr)) { UNDEFINED(pc, insn, "illegal bitmasks"); return; } PRINTF("eor\t%s, %s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), DecodeBitMasks(sf, n, imms, immr)); } OP6FUNC(op_eor_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "eor", NULL, NULL); } OP0FUNC(op_eret) { PRINTF("eret\n"); } OP6FUNC(op_ror_imm, sf, n, Rm, imms, Rn, Rd) { if (((sf ^ n) != 0) || (n == 0 && imms >= 0x20)) { UNDEFINED(pc, insn, "illegal sf and N"); return; } /* ALIAS: extr */ if (Rn == Rm) { PRINTF("ror\t%s, %s, #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), imms); } else { PRINTF("extr\t%s, %s, %s, #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), imms); } } #define CRm_OP2(crm,op) ((crm) << 3 | (op)) static const char *hint_table[] = { [CRm_OP2(0, 0)] = "nop", [CRm_OP2(0, 1)] = "yield", [CRm_OP2(0, 2)] = "wfe", [CRm_OP2(0, 3)] = "wfi", [CRm_OP2(0, 4)] = "sev", [CRm_OP2(0, 5)] = "sevl", [CRm_OP2(0, 7)] = "xpaclri", [CRm_OP2(1, 0)] = "pacia1716", [CRm_OP2(1, 2)] = "pacib1716", [CRm_OP2(1, 4)] = "autia1716", [CRm_OP2(1, 6)] = "autib1716", [CRm_OP2(2, 0)] = "esb", [CRm_OP2(2, 1)] = "psb\tcsync", [CRm_OP2(2, 2)] = "tsb\tcsync", [CRm_OP2(2, 4)] = "csdb", [CRm_OP2(3, 0)] = "paciaz", [CRm_OP2(3, 1)] = "paciasp", [CRm_OP2(3, 2)] = "pacibz", [CRm_OP2(3, 3)] = "pacibsp", [CRm_OP2(3, 4)] = "autiaz", [CRm_OP2(3, 5)] = "autiasp", [CRm_OP2(3, 6)] = "autibz", [CRm_OP2(3, 7)] = "autibsp", [CRm_OP2(4, 0)] = "bti", [CRm_OP2(4, 2)] = "bti\tc", [CRm_OP2(4, 4)] = "bti\tj", [CRm_OP2(4, 6)] = "bti\tjc", }; OP2FUNC(op_hint, CRm, op2) { const uint64_t op = CRm_OP2(CRm, op2); /* ALIAS: nop,sev,sevl,wfe,wfi,yield,etc,.. */ if (op < __arraycount(hint_table) && hint_table[op] != NULL) { PRINTF("%s\n", hint_table[op]); } else { PRINTF("hint\t#0x%"PRIx64"\n", op); } } OP1FUNC(op_hlt, imm16) { PRINTF("hlt\t#0x%"PRIx64"\n", imm16); } OP1FUNC(op_hvc, imm16) { PRINTF("hvc\t#0x%"PRIx64"\n", imm16); } OP1FUNC(op_isb, CRm) { if (CRm == 15) PRINTF("isb\n"); else PRINTF("isb\t#0x%"PRIx64"\n", CRm); } OP3FUNC(op_ldar, size, Rn, Rt) { PRINTF("ldar\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_ldarb, Rn, Rt) { PRINTF("ldarb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_ldarh, Rn, Rt) { PRINTF("ldarh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP4FUNC(op_ldaxp, size, Rt2, Rn, Rt) { PRINTF("ldaxp\t%s, %s, [%s]\n", ZREGNAME(size, Rt), ZREGNAME(size, Rt2), SREGNAME(1, Rn)); } OP3FUNC(op_ldaxr, size, Rn, Rt) { PRINTF("ldaxr\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_ldaxrb, Rn, Rt) { PRINTF("ldaxrb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_ldaxrh, Rn, Rt) { PRINTF("ldaxrh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP5FUNC(op_ldnp, sf, imm7, Rt2, Rn, Rt) { if (imm7 == 0) { PRINTF("ldnp\t%s, %s, [%s]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn)); } else { PRINTF("ldnp\t%s, %s, [%s,#%"PRId64"]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } } OP5FUNC(op_ldp_postidx, sf, imm7, Rt2, Rn, Rt) { PRINTF("ldp\t%s, %s, [%s],#%"PRId64"\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } OP5FUNC(op_ldp_preidx, sf, imm7, Rt2, Rn, Rt) { PRINTF("ldp\t%s, %s, [%s,#%"PRId64"]!\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } OP5FUNC(op_ldp_signed, sf, imm7, Rt2, Rn, Rt) { if (imm7 == 0) { PRINTF("ldp\t%s, %s, [%s]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn)); } else { PRINTF("ldp\t%s, %s, [%s,#%"PRId64"]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } } OP4FUNC(op_ldpsw_postidx, imm7, Rt2, Rn, Rt) { PRINTF("ldpsw\t%s, %s, [%s],#%"PRId64"\n", ZREGNAME(1, Rt), ZREGNAME(1, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, 4)); } OP4FUNC(op_ldpsw_preidx, imm7, Rt2, Rn, Rt) { PRINTF("ldpsw\t%s, %s, [%s,#%"PRId64"]!\n", ZREGNAME(1, Rt), ZREGNAME(1, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, 4)); } OP4FUNC(op_ldpsw_signed, imm7, Rt2, Rn, Rt) { if (imm7 == 0) { PRINTF("ldpsw\t%s, %s, [%s]\n", ZREGNAME(1, Rt), ZREGNAME(1, Rt2), SREGNAME(1, Rn)); } else { PRINTF("ldpsw\t%s, %s, [%s,#%"PRId64"]\n", ZREGNAME(1, Rt), ZREGNAME(1, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, 4)); } } OP4FUNC(op_ldr_immpostidx, size, imm9, Rn, Rt) { PRINTF("ldr\t%s, [%s],#%"PRId64"\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_ldr_immpreidx, size, imm9, Rn, Rt) { PRINTF("ldr\t%s, [%s,#%"PRId64"]!\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_ldr_immunsign, size, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("ldr\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldr\t%s, [%s,#%"PRId64"]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, (size == 0) ? 4 : 8)); } } OP3FUNC(op_ldr_literal, size, imm19, Rt) { PRINTF("ldr\t%s, ", ZREGNAME(size, Rt)); PRINTADDR(SignExtend(19, imm19, 4) + pc); PRINTF("\n"); } OP6FUNC(op_ldr_reg, size, Rm, option, shift, Rn, Rt) { regoffset_x_common(di, pc, insn, size, Rm, option, shift, Rn, Rt, "ldr"); } OP3FUNC(op_ldrb_immpostidx, imm9, Rn, Rt) { PRINTF("ldrb\t%s, [%s],#%"PRId64"\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_ldrb_immpreidx, imm9, Rn, Rt) { PRINTF("ldrb\t%s, [%s,#%"PRId64"]!\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_ldrb_immunsign, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("ldrb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldrb\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 1)); } } OP5FUNC(op_ldrb_reg, Rm, option, shift, Rn, Rt) { regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrb"); } OP3FUNC(op_ldrh_immpostidx, imm9, Rn, Rt) { PRINTF("ldrh\t%s, [%s],#%"PRId64"\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_ldrh_immpreidx, imm9, Rn, Rt) { PRINTF("ldrh\t%s, [%s,#%"PRId64"]!\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_ldrh_immunsign, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("ldrh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldrh\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 2)); } } OP5FUNC(op_ldrh_reg, Rm, option, shift, Rn, Rt) { regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, 0, "ldrh"); } OP4FUNC(op_ldrsb_immpostidx, opc, imm9, Rn, Rt) { PRINTF("ldrsb\t%s, [%s],#%"PRId64"\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_ldrsb_immpreidx, opc, imm9, Rn, Rt) { PRINTF("ldrsb\t%s, [%s,#%"PRId64"]!\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_ldrsb_immunsign, opc, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("ldrsb\t%s, [%s]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn)); } else { PRINTF("ldrsb\t%s, [%s,#%"PRId64"]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 1)); } } OP6FUNC(op_ldrsb_reg, opc, Rm, option, shift, Rn, Rt) { regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrsb"); } OP4FUNC(op_ldrsh_immpostidx, opc, imm9, Rn, Rt) { PRINTF("ldrsh\t%s, [%s],#%"PRId64"\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_ldrsh_immpreidx, opc, imm9, Rn, Rt) { PRINTF("ldrsh\t%s, [%s,#%"PRId64"]!\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_ldrsh_immunsign, opc, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("ldrsh\t%s, [%s]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn)); } else { PRINTF("ldrsh\t%s, [%s,#%"PRId64"]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 2)); } } OP6FUNC(op_ldrsh_reg, opc, Rm, option, shift, Rn, Rt) { regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, opc ^ 1, "ldrsh"); } OP3FUNC(op_ldrsw_immpostidx, imm9, Rn, Rt) { PRINTF("ldrsw\t%s, [%s],#%"PRId64"\n", ZREGNAME(1, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_ldrsw_immpreidx, imm9, Rn, Rt) { PRINTF("ldrsw\t%s, [%s,#%"PRId64"]!\n", ZREGNAME(1, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_ldrsw_immunsign, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("ldrsw\t%s, [%s]\n", ZREGNAME(1, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldrsw\t%s, [%s,#%"PRId64"]\n", ZREGNAME(1, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 4)); } } OP2FUNC(op_ldrsw_literal, imm19, Rt) { PRINTF("ldrsw\t%s, ", ZREGNAME(1, Rt)); PRINTADDR(SignExtend(19, imm19, 4) + pc); PRINTF("\n"); } OP5FUNC(op_ldrsw_reg, Rm, option, shift, Rn, Rt) { regoffset_w_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrsw"); } OP4FUNC(op_ldtr, size, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldtr\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldtr\t%s, [%s,#%"PRId64"]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_ldtrb, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldtrb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldtrb\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_ldtrh, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldtrh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldtrh\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP4FUNC(op_ldtrsb, opc, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldtrsb\t%s, [%s]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn)); } else { PRINTF("ldtrsb\t%s, [%s,#%"PRId64"]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP4FUNC(op_ldtrsh, opc, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldtrsh\t%s, [%s]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn)); } else { PRINTF("ldtrsh\t%s, [%s,#%"PRId64"]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_ldtrsw, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldtrsw\t%s, [%s]\n", ZREGNAME(1, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldtrsw\t%s, [%s,#%"PRId64"]\n", ZREGNAME(1, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP4FUNC(op_ldur, size, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldur\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldur\t%s, [%s,#%"PRId64"]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_ldurb, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldurb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldurb\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_ldurh, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldurh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldurh\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP4FUNC(op_ldursb, opc, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldursb\t%s, [%s]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn)); } else { PRINTF("ldursb\t%s, [%s,#%"PRId64"]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP4FUNC(op_ldursh, opc, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldursh\t%s, [%s]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn)); } else { PRINTF("ldursh\t%s, [%s,#%"PRId64"]\n", ZREGNAME((opc ^ 1), Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_ldursw, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("ldursw\t%s, [%s]\n", ZREGNAME(1, Rt), SREGNAME(1, Rn)); } else { PRINTF("ldursw\t%s, [%s,#%"PRId64"]\n", ZREGNAME(1, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP4FUNC(op_ldxp, size, Rt2, Rn, Rt) { PRINTF("ldxp\t%s, %s, [%s]\n", ZREGNAME(size, Rt), ZREGNAME(size, Rt2), SREGNAME(1, Rn)); } OP3FUNC(op_ldxr, size, Rn, Rt) { PRINTF("ldxr\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_ldxrb, Rn, Rt) { PRINTF("ldxrb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_ldxrh, Rn, Rt) { PRINTF("ldxrh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP6FUNC(op_ubfm, sf, n, immr, imms, Rn, Rd) { const uint64_t bitwidth = (sf == 0) ? 32 : 64; /* ALIAS: lsr_imm,ubfiz,ubfm,ubfx,uxtb,uxth */ if ((imms != (bitwidth - 1)) && ((imms + 1) == immr)) { PRINTF("lsl\t%s, %s, #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), bitwidth - immr); } else if (imms == (bitwidth - 1)) { PRINTF("lsr\t%s, %s, #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), immr); } else if (imms < immr) { PRINTF("ubfiz\t%s, %s, #%"PRIu64", #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), (bitwidth - immr) & (bitwidth - 1), (imms + 1) & (bitwidth - 1)); } else if (BFXPreferred(sf, 1, imms, immr)) { PRINTF("ubfx\t%s, %s, #%"PRIu64", #%"PRIu64"\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), immr, (imms - immr + 1) & (bitwidth - 1)); } else if ((immr == 0) && (imms == 7)) { PRINTF("uxtb\t%s, %s\n", ZREGNAME(0, Rd), ZREGNAME(0, Rn)); } else if ((immr == 0) && (imms == 15)) { PRINTF("uxth\t%s, %s\n", ZREGNAME(0, Rd), ZREGNAME(0, Rn)); } else { UNDEFINED(pc, insn, "undefined"); } } OP4FUNC(op_lsl_reg, sf, Rm, Rn, Rd) { /* ALIAS: lslv */ /* "lsl" always the preferred disassembly */ PRINTF("lsl\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } OP4FUNC(op_lsr_reg, sf, Rm, Rn, Rd) { /* ALIAS: lsrv */ /* "lsr" always the preferred disassembly */ PRINTF("lsr\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } OP5FUNC(op_madd, sf, Rm, Ra, Rn, Rd) { /* ALIAS: mul */ if (Ra == 31) { PRINTF("mul\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } else { PRINTF("madd\t%s, %s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), ZREGNAME(sf, Ra)); } } OP5FUNC(op_msub, sf, Rm, Ra, Rn, Rd) { /* ALIAS: mneg */ if (Ra == 31) { PRINTF("mneg\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } else { PRINTF("msub\t%s, %s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm), ZREGNAME(sf, Ra)); } } OP6FUNC(op_orr_imm, sf, n, immr, imms, Rn, Rd) { if (!ValidBitMasks(sf, n, imms, immr)) { UNDEFINED(pc, insn, "illegal bitmasks"); return; } /* ALIAS: mov_bmimm */ #if 1 /* to distinguish from mov_iwimm */ if ((Rn == 31) && !MoveWidePreferred(sf, n, imms, immr)) { #else /* "orr Rd, XZR, #imm" -> "mov Rd, #imm" */ (void)MoveWidePreferred; if (Rn == 31) { #endif PRINTF("mov\t%s, #0x%"PRIx64"\n", SREGNAME(sf, Rd), DecodeBitMasks(sf, n, imms, immr)); } else { PRINTF("orr\t%s, %s, #0x%"PRIx64"\n", SREGNAME(sf, Rd), ZREGNAME(sf, Rn), DecodeBitMasks(sf, n, imms, immr)); } } OP4FUNC(op_movn, sf, hw, imm16, Rd) { const uint64_t mask = (sf == 0) ? 0xffffffff : 0xffffffffffffffffUL; if ((sf == 0) && (hw >= 2)) { UNDEFINED(pc, insn, "illegal size"); return; } /* ALIAS: mov_iwimm */ if ((hw == 0) || (imm16 == 0)) { PRINTF("mov\t%s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), (~(ZeroExtend(16, imm16, 1) & mask)) & mask); } else { /* movn */ const uint64_t shift = hw * 16; PRINTF("mov\t%s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), ~(ZeroExtend(16, imm16, 1) << shift) & mask); } } OP6FUNC(op_orr_reg, sf, shift, Rm, imm6, Rn, Rd) { /* ALIAS: mov_reg */ if ((Rn == 31) && (imm6 == 0)) { PRINTF("mov\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rm)); } else { shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "orr", NULL, NULL); } } OP4FUNC(op_movz, sf, hw, imm16, Rd) { /* ALIAS: mov_wimm */ if ((hw == 0) || (imm16 == 0)) { PRINTF("mov\t%s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), ZeroExtend(16, imm16, 1)); } else { const int shift = hw * 16; #if 0 PRINTF("movz\t%s, #0x%lx, lsl #%d\n", ZREGNAME(sf, Rd), ZeroExtend(16, imm16, 1), shift); #else /* same as objdump */ PRINTF("mov\t%s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), ZeroExtend(16, imm16, 1) << shift); #endif } } OP4FUNC(op_movk, sf, hw, imm16, Rd) { const int shift = hw * 16; if (hw == 0) { PRINTF("movk\t%s, #0x%"PRIx64"\n", ZREGNAME(sf, Rd), ZeroExtend(16, imm16, 1)); } else { PRINTF("movk\t%s, #0x%"PRIx64", lsl #%d\n", ZREGNAME(sf, Rd), ZeroExtend(16, imm16, 1), shift); } } OP6FUNC(op_mrs, op0, op1, CRn, CRm, op2, Rt) { char buf[SYSREGNAMEBUFLEN]; PRINTF("mrs\t%s, %s\n", ZREGNAME(1, Rt), RSYSREGNAME(buf, sizeof(buf), op0, op1, CRn, CRm, op2)); } OP6FUNC(op_msr, op0, op1, CRn, CRm, op2, Rt) { char buf[SYSREGNAMEBUFLEN]; PRINTF("msr\t%s, %s\n", WSYSREGNAME(buf, sizeof(buf), op0, op1, CRn, CRm, op2), ZREGNAME(1, Rt)); } OP3FUNC(op_msr_imm, op1, CRm, op2) { const char *pstatefield; #define MSRIMM_OP(op1, op2) (((op1) << 3) | (op2)) switch (MSRIMM_OP(op1, op2)) { case MSRIMM_OP(0, 0): PRINTF("cfinv\n"); return; case MSRIMM_OP(0, 1): PRINTF("xaflag\n"); return; case MSRIMM_OP(0, 2): PRINTF("axflag\n"); return; case MSRIMM_OP(0, 3): pstatefield = "uao"; break; case MSRIMM_OP(0, 4): pstatefield = "pan"; break; case MSRIMM_OP(0, 5): pstatefield = "spsel"; break; case MSRIMM_OP(3, 1): pstatefield = "ssbs"; break; case MSRIMM_OP(3, 2): pstatefield = "dit"; break; case MSRIMM_OP(3, 4): pstatefield = "tco"; break; case MSRIMM_OP(3, 6): pstatefield = "daifset"; break; case MSRIMM_OP(3, 7): pstatefield = "daifclr"; break; default: UNDEFINED(pc, insn, "illegal op1/op2"); return; } PRINTF("msr\t%s, #0x%"PRIx64"\n", pstatefield, CRm); } OP6FUNC(op_orn, sf, shift, Rm, imm6, Rn, Rd) { /* ALIAS: mvn */ shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "orn", "mvn", NULL); } OP6FUNC(op_sub_shiftreg, sf, shift, Rm, imm6, Rn, Rd) { /* ALIAS: neg */ shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, "sub", "neg", NULL); } OP4FUNC(op_sbc, sf, Rm, Rn, Rd) { /* ALIAS: ngc */ if (Rn == 31) { PRINTF("ngc\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rm)); } else { PRINTF("sbc\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } } OP4FUNC(op_sbcs, sf, Rm, Rn, Rd) { /* ALIAS: ngcs */ if (Rn == 31) { PRINTF("ngcs\t%s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rm)); } else { PRINTF("sbcs\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } } OP3FUNC(op_prfm_imm, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("prfm\t%s, [%s]\n", PREFETCHNAME(Rt), SREGNAME(1, Rn)); } else { PRINTF("prfm\t%s, [%s,#%"PRId64"]\n", PREFETCHNAME(Rt), SREGNAME(1, Rn), SignExtend(12, imm12, 8)); } } OP2FUNC(op_prfm_literal, imm19, Rt) { PRINTF("prfm\t%s, ", PREFETCHNAME(Rt)); PRINTADDR(SignExtend(19, imm19, 4) + pc); PRINTF("\n"); } OP5FUNC(op_prfm_reg, Rm, option, shift, Rn, Rt) { int r; if ((r = regoffset_option_to_r(option)) < 0) { UNDEFINED(pc, insn, "illegal option"); return; } if (shift == 0) { PRINTF("prfm\t%s, [%s,%s%s]\n", PREFETCHNAME(Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx")); } else { PRINTF("prfm\t%s, [%s,%s,%s #%d]\n", PREFETCHNAME(Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"), 3); } } OP3FUNC(op_prfum, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("prfum\t%s, [%s]\n", PREFETCHNAME(Rt), SREGNAME(1, Rn)); } else { PRINTF("prfum\t%s, [%s,#%"PRId64"]\n", PREFETCHNAME(Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP1FUNC(op_ret, Rn) { if (Rn == 30) PRINTF("ret\n"); else PRINTF("ret\t%s\n", ZREGNAME(1, Rn)); } OP4FUNC(op_rev, sf, opc, Rn, Rd) { /* * sf opc insn * -- --- ------------- * 0 00 rbit Wd,Wn * 0 01 rev16 Wd,Wn * 0 10 rev Wd,Wn * 0 11 undefined * 1 00 rbit Xd,Xn * 1 01 rev16 Xd,Xn * 1 10 rev32 Xd,Xn * 1 11 rev Xd,Xn */ const char *const opcode[2][4] = { { "rbit", "rev16", "rev", NULL }, { "rbit", "rev16", "rev32", "rev" } }; const char *const op = opcode[sf][opc]; if (op == NULL) { UNDEFINED(pc, insn, "undefined"); return; } PRINTF("%s\t%s, %s\n", op, ZREGNAME(sf, Rd), ZREGNAME(sf, Rn)); } OP4FUNC(op_ror_reg, sf, Rm, Rn, Rd) { /* ALIAS: rorv */ /* "ror" always the preferred disassembly */ PRINTF("ror\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } OP4FUNC(op_sdiv, sf, Rm, Rn, Rd) { PRINTF("sdiv\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } OP4FUNC(op_smaddl, Rm, Ra, Rn, Rd) { /* ALIAS: smull */ if (Ra == 31) { PRINTF("smull\t%s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(0, Rn), ZREGNAME(0, Rm)); } else { PRINTF("smaddl\t%s, %s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(0, Rn), ZREGNAME(0, Rm), ZREGNAME(1, Ra)); } } OP1FUNC(op_smc, imm16) { PRINTF("smc\t#0x%"PRIx64"\n", imm16); } OP4FUNC(op_smsubl, Rm, Ra, Rn, Rd) { /* ALIAS: smnegl */ if (Ra == 31) { PRINTF("smnegl\t%s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(0, Rn), ZREGNAME(0, Rm)); } else { PRINTF("smsubl\t%s, %s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(0, Rn), ZREGNAME(0, Rm), ZREGNAME(1, Ra)); } } OP3FUNC(op_smulh, Rm, Rn, Rd) { PRINTF("smulh\t%s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(1, Rn), ZREGNAME(1, Rm)); } OP3FUNC(op_stlr, size, Rn, Rt) { PRINTF("stlr\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_stlrb, Rn, Rt) { PRINTF("stlrb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP2FUNC(op_stlrh, Rn, Rt) { PRINTF("stlrh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP5FUNC(op_stlxp, size, Rs, Rt2, Rn, Rt) { PRINTF("stlxp\t%s, %s, [%s]\n", ZREGNAME(size, Rt), ZREGNAME(size, Rt2), SREGNAME(1, Rn)); } OP4FUNC(op_stlxr, size, Rs, Rn, Rt) { PRINTF("stlxr\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } OP3FUNC(op_stlxrb, Rs, Rn, Rt) { PRINTF("stlxrb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP3FUNC(op_stlxrh, Rs, Rn, Rt) { PRINTF("stlxrh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP5FUNC(op_stnp, sf, imm7, Rt2, Rn, Rt) { if (imm7 == 0) { PRINTF("stnp\t%s, %s, [%s]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn)); } else { PRINTF("stnp\t%s, %s, [%s,#%"PRId64"]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } } OP5FUNC(op_stp_postidx, sf, imm7, Rt2, Rn, Rt) { PRINTF("stp\t%s, %s, [%s],#%"PRId64"\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } OP5FUNC(op_stp_preidx, sf, imm7, Rt2, Rn, Rt) { PRINTF("stp\t%s, %s, [%s,#%"PRId64"]!\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } OP5FUNC(op_stp_signed, sf, imm7, Rt2, Rn, Rt) { if (imm7 == 0) { PRINTF("stp\t%s, %s, [%s]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn)); } else { PRINTF("stp\t%s, %s, [%s,#%"PRId64"]\n", ZREGNAME(sf, Rt), ZREGNAME(sf, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (sf == 0) ? 4 : 8)); } } OP4FUNC(op_str_immpostidx, size, imm9, Rn, Rt) { PRINTF("str\t%s, [%s],#%"PRId64"\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_str_immpreidx, size, imm9, Rn, Rt) { PRINTF("str\t%s, [%s,#%"PRId64"]!\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP4FUNC(op_str_immunsign, size, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("str\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } else { PRINTF("str\t%s, [%s,#%"PRIu64"]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, (size == 0) ? 4 : 8)); } } OP6FUNC(op_str_reg, size, Rm, option, shift, Rn, Rt) { regoffset_x_common(di, pc, insn, size, Rm, option, shift, Rn, Rt, "str"); } OP3FUNC(op_strb_immpostidx, imm9, Rn, Rt) { PRINTF("strb\t%s, [%s],#%"PRId64"\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_strb_immpreidx, imm9, Rn, Rt) { PRINTF("strb\t%s, [%s,#%"PRId64"]!\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_strb_immunsign, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("strb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("strb\t%s, [%s,#%"PRIu64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 1)); } } OP5FUNC(op_strb_reg, Rm, option, shift, Rn, Rt) { regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "strb"); } OP3FUNC(op_strh_immpostidx, imm9, Rn, Rt) { PRINTF("strh\t%s, [%s],#%"PRId64"\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_strh_immpreidx, imm9, Rn, Rt) { PRINTF("strh\t%s, [%s,#%"PRId64"]!\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP3FUNC(op_strh_immunsign, imm12, Rn, Rt) { if (imm12 == 0) { PRINTF("strh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("strh\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 2)); } } OP5FUNC(op_strh_reg, Rm, option, shift, Rn, Rt) { regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, 0, "strh"); } OP4FUNC(op_sttr, size, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("sttr\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } else { PRINTF("sttr\t%s, [%s,#%"PRId64"]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_sttrb, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("sttrb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("sttrb\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_sttrh, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("sttrh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("sttrh\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP4FUNC(op_stur, size, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("stur\t%s, [%s]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn)); } else { PRINTF("stur\t%s, [%s,#%"PRId64"]\n", ZREGNAME(size, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_sturb, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("sturb\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("sturb\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP3FUNC(op_sturh, imm9, Rn, Rt) { if (imm9 == 0) { PRINTF("sturh\t%s, [%s]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn)); } else { PRINTF("sturh\t%s, [%s,#%"PRId64"]\n", ZREGNAME(0, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } } OP5FUNC(op_stxp, size, Rs, Rt2, Rn, Rt) { PRINTF("stxp\t%s, %s, [%s]\n", ZREGNAME(size, Rt), ZREGNAME(size, Rt2), SREGNAME(1, Rn)); } OP4FUNC(op_stxr, size, Rs, Rn, Rt) { PRINTF("stxr\t%s, %s, [%s]\n", ZREGNAME(0, Rs), ZREGNAME(size, Rt), SREGNAME(1, Rn)); } OP3FUNC(op_stxrb, Rs, Rn, Rt) { PRINTF("stxrb\t%s, %s, [%s]\n", ZREGNAME(0, Rs), ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP3FUNC(op_stxrh, Rs, Rn, Rt) { PRINTF("stxrh\t%s, %s, [%s]\n", ZREGNAME(0, Rs), ZREGNAME(0, Rt), SREGNAME(1, Rn)); } OP6FUNC(op_sub_extreg, sf, Rm, option, imm3, Rn, Rd) { extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd, "sub", NULL); } OP5FUNC(op_sub_imm, sf, shift, imm12, Rn, Rd) { if (shift & 2) { UNDEFINED(pc, insn, "illegal shift"); return; } PRINTF("sub\t%s, %s, #0x%"PRIx64"%s\n", SREGNAME(sf, Rd), SREGNAME(sf, Rn), ZeroExtend(12, imm12, 1), SHIFTOP2(shift, "", ", lsl #12")); } OP1FUNC(op_svc, imm16) { PRINTF("svc\t#0x%"PRIx64"\n", imm16); } OP5FUNC(op_sysl, op1, CRn, CRm, op2, Rt) { PRINTF("sysl\t%s, #%"PRIu64", %s, %s, #%"PRIu64"\n", ZREGNAME(1, Rt), op1, CREGNAME(CRn), CREGNAME(CRm), op2); } OP4FUNC(op_tbnz, b5, b40, imm14, Rt) { uint64_t bit = (b5 << 5) + b40; PRINTF("tbnz\t%s, #%"PRIu64", ", ZREGNAME(b5, Rt), bit); PRINTADDR(SignExtend(14, imm14, 4) + pc); PRINTF("\n"); } OP4FUNC(op_tbz, b5, b40, imm14, Rt) { uint64_t bit = (b5 << 5) + b40; PRINTF("tbz\t%s, #%"PRIu64", ", ZREGNAME(b5, Rt), bit); PRINTADDR(SignExtend(14, imm14, 4) + pc); PRINTF("\n"); } OP4FUNC(op_udiv, sf, Rm, Rn, Rd) { PRINTF("udiv\t%s, %s, %s\n", ZREGNAME(sf, Rd), ZREGNAME(sf, Rn), ZREGNAME(sf, Rm)); } OP4FUNC(op_umaddl, Rm, Ra, Rn, Rd) { /* ALIAS: umull */ if (Ra == 31) { PRINTF("umull\t%s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(0, Rn), ZREGNAME(0, Rm)); } else { PRINTF("umaddl\t%s, %s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(0, Rn), ZREGNAME(0, Rm), ZREGNAME(1, Ra)); } } OP4FUNC(op_umsubl, Rm, Ra, Rn, Rd) { /* ALIAS: umnegl */ if (Ra == 31) { PRINTF("umnegl\t%s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(1, Rn), ZREGNAME(1, Rm)); } else { PRINTF("umsubl\t%s, %s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(1, Rn), ZREGNAME(1, Rm), ZREGNAME(1, Ra)); } } OP3FUNC(op_umulh, Rm, Rn, Rd) { PRINTF("umulh\t%s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(1, Rn), ZREGNAME(1, Rm)); } /* * load/store SIMD instructions */ OP6FUNC(op_simd_ldstnp, opc, l, imm7, Rt2, Rn, Rt) { const char *op = (l == 0) ? "stnp" : "ldnp"; const int regsz = (opc & 3) + 2; if (opc == 3) { UNDEFINED(pc, insn, "illegal opc"); return; } if (imm7 == 0) { PRINTF("%s\t%s, %s, [%s]\n", op, FREGNAME(regsz, Rt), FREGNAME(regsz, Rt2), SREGNAME(1, Rn)); } else { PRINTF("%s\t%s, %s, [%s,#%"PRId64"]\n", op, FREGNAME(regsz, Rt), FREGNAME(regsz, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (4 << opc))); } } OP6FUNC(op_simd_ldstp_postidx, opc, l, imm7, Rt2, Rn, Rt) { const char *op = (l == 0) ? "stp" : "ldp"; const int regsz = (opc & 3) + 2; PRINTF("%s\t%s, %s, [%s],#%"PRId64"\n", op, FREGNAME(regsz, Rt), FREGNAME(regsz, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (4 << opc))); } OP6FUNC(op_simd_ldstp_preidx, opc, l, imm7, Rt2, Rn, Rt) { const char *op = (l == 0) ? "stp" : "ldp"; const int regsz = (opc & 3) + 2; PRINTF("%s\t%s, %s, [%s,#%"PRId64"]!\n", op, FREGNAME(regsz, Rt), FREGNAME(regsz, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (4 << opc))); } OP6FUNC(op_simd_ldstp_signed, opc, l, imm7, Rt2, Rn, Rt) { const char *op = (l == 0) ? "stp" : "ldp"; const int regsz = (opc & 3) + 2; if (opc == 3) { UNDEFINED(pc, insn, "illegal opc"); return; } if (imm7 == 0) { PRINTF("%s\t%s, %s, [%s]\n", op, FREGNAME(regsz, Rt), FREGNAME(regsz, Rt2), SREGNAME(1, Rn)); } else { PRINTF("%s\t%s, %s, [%s,#%"PRId64"]\n", op, FREGNAME(regsz, Rt), FREGNAME(regsz, Rt2), SREGNAME(1, Rn), SignExtend(7, imm7, (4 << opc))); } } static inline int simd_ldstr_regsz(uint64_t size, uint64_t opc) { if ((opc & 2) == 0) return size; if (size == 0) return 4; return -1; } OP5FUNC(op_simd_ldstr_immpostidx, size, opc, imm9, Rn, Rt) { const char *op = ((opc & 1) == 0) ? "str" : "ldr"; int regsz; if ((regsz = simd_ldstr_regsz(size, opc)) < 0) { UNDEFINED(pc, insn, "illegal size/opc"); return; } PRINTF("%s\t%s, [%s],#%"PRId64"\n", op, FREGNAME(regsz, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP5FUNC(op_simd_ldstr_immpreidx, size, opc, imm9, Rn, Rt) { const char *op = ((opc & 1) == 0) ? "str" : "ldr"; int regsz; if ((regsz = simd_ldstr_regsz(size, opc)) < 0) { UNDEFINED(pc, insn, "illegal size/opc"); return; } PRINTF("%s\t%s, [%s,#%"PRId64"]!\n", op, FREGNAME(regsz, Rt), SREGNAME(1, Rn), SignExtend(9, imm9, 1)); } OP5FUNC(op_simd_ldstr_immunsign, size, opc, imm12, Rn, Rt) { const char *op = ((opc & 1) == 0) ? "str" : "ldr"; int regsz; if ((regsz = simd_ldstr_regsz(size, opc)) < 0) { UNDEFINED(pc, insn, "illegal size/opc"); return; } if (imm12 == 0) { PRINTF("%s\t%s, [%s]\n", op, FREGNAME(regsz, Rt), SREGNAME(1, Rn)); } else { PRINTF("%s\t%s, [%s,#%"PRIu64"]\n", op, FREGNAME(regsz, Rt), SREGNAME(1, Rn), ZeroExtend(12, imm12, 1 << regsz)); } } OP7FUNC(op_simd_ldstr_reg, size, opc, Rm, option, S, Rn, Rt) { const char *op = ((opc & 1) == 0) ? "str" : "ldr"; int regsz, r; if ((regsz = simd_ldstr_regsz(size, opc)) < 0) { UNDEFINED(pc, insn, "illegal size/opc"); return; } if ((r = regoffset_option_to_r(option)) < 0) { UNDEFINED(pc, insn, "illegal option"); return; } if (S == 0) { PRINTF("%s\t%s, [%s,%s%s]\n", op, FREGNAME(regsz, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx")); } else { u_int amount = regsz; PRINTF("%s\t%s, [%s,%s,%s #%u]\n", op, FREGNAME(regsz, Rt), SREGNAME(1, Rn), ZREGNAME(r, Rm), SHIFTOP8(option, "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"), amount); } } OP4FUNC(op_simd_aes, m, d, Rn, Rt) { const char *aesop[2][2] = { { "aese", "aesd", }, { "aesmc", "aesimc" } }; PRINTF("%s\t%s.16b, %s.16b\n", aesop[m & 1][d & 1], VREGNAME(Rn), VREGNAME(Rt)); } OP4FUNC(op_simd_sha_reg3, Rm, op, Rn, Rd) { const char *shaop[8] = { "sha1c", "sha1p", "sha1m", "sha1su0", "sha256h", "sha256h2", "sha256su1", NULL }; switch (op) { case 0: case 1: case 2: PRINTF("%s\t%s, %s, %s.4s\n", shaop[op], FREGNAME(FREGSZ_Q, Rd), FREGNAME(FREGSZ_S, Rn), VREGNAME(Rm)); break; case 4: case 5: PRINTF("%s\t%s, %s, %s.4s\n", shaop[op], FREGNAME(FREGSZ_Q, Rd), FREGNAME(FREGSZ_Q, Rn), VREGNAME(Rm)); break; case 3: case 6: PRINTF("%s\t%s.4s, %s.4s, %s.4s\n", shaop[op], VREGNAME(Rd), VREGNAME(Rn), VREGNAME(Rm)); break; default: UNDEFINED(pc, insn, "illegal sha operation"); break; } } OP3FUNC(op_simd_sha_reg2, op, Rn, Rd) { const char *shaop[4] = { "sha1h", "sha1su1", "sha256su0", NULL }; switch (op) { case 0: PRINTF("%s\t%s, %s\n", shaop[op], FREGNAME(FREGSZ_S, Rd), FREGNAME(FREGSZ_S, Rn)); break; case 1: case 2: PRINTF("%s\t%s.4s, %s.4s\n", shaop[op], VREGNAME(Rd), VREGNAME(Rn)); break; default: UNDEFINED(pc, insn, "illegal sha operation"); break; } } OP4FUNC(op_simd_sha512_reg3, Rm, op, Rn, Rd) { const char *shaop[4] = { "sha512h", "sha512h2", "sha512su1", "rax1" }; switch (op) { case 0: case 1: PRINTF("%s\t%s, %s, %s.2d\n", shaop[op], FREGNAME(FREGSZ_Q, Rd), FREGNAME(FREGSZ_Q, Rn), VREGNAME(Rm)); break; case 2: case 3: PRINTF("%s\t%s.2d, %s,.2d %s.2d\n", shaop[op], VREGNAME(Rd), VREGNAME(Rn), VREGNAME(Rm)); break; } } OP3FUNC(op_simd_sha512_reg2, op, Rn, Rd) { const char *shaop[4] = { "sha512su0", "sm4e", NULL, NULL }; switch (op) { case 0: case 1: PRINTF("%s\t%s.2d, %s.2d\n", shaop[op], VREGNAME(Rd), VREGNAME(Rn)); break; default: UNDEFINED(pc, insn, "illegal sha512 operation"); break; } } OP5FUNC(op_simd_pmull, q, size, Rm, Rn, Rd) { const char *op = (q == 0) ? "pmull" : "pmull2"; const char *regspec_Ta[4] = { "8h", NULL, NULL, "1q" }; const char *regspec_Tb[8] = { "8b", "16b", NULL, NULL, NULL, NULL, "1d", "2d" }; if ((regspec_Ta[size & 3] != NULL) && (regspec_Tb[((size & 3) << 1) + (q & 1)] != NULL)) { PRINTF("%s\t%s.%s, %s.%s, %s.%s\n", op, VREGNAME(Rd), regspec_Ta[size & 3], VREGNAME(Rn), regspec_Tb[((size & 3) << 1) + (q & 1)], VREGNAME(Rd), regspec_Tb[((size & 3) << 1) + (q & 1)]); } else { UNDEFINED(pc, insn, "illegal pmull size"); } } OP1FUNC(op_eretaa, m) { if (m == 0) PRINTF("eretaa\n"); else PRINTF("eretab\n"); } OP1FUNC(op_retaa, m) { if (m == 0) PRINTF("retaa\n"); else PRINTF("retab\n"); } OP4FUNC(op_blraa, z, m, Rn, Rm) { if (z == 0) { if (Rm != 31) { UNDEFINED(pc, insn, "undefined"); } else { PRINTF("%s\t%s\n", SHIFTOP2(m, "blraaz", "blrabz"), SREGNAME(1, Rn)); } } else { PRINTF("%s\t%s, %s\n", SHIFTOP2(m, "blraa", "blrab"), SREGNAME(1, Rn), SREGNAME(1, Rm)); } } OP4FUNC(op_braa, z, m, Rn, Rm) { if (z == 0) { if (Rm != 31) { UNDEFINED(pc, insn, "undefined"); } else { PRINTF("%s\t%s\n", SHIFTOP2(m, "braaz", "brabz"), SREGNAME(1, Rn)); } } else { PRINTF("%s\t%s, %s\n", SHIFTOP2(m, "braa", "brab"), SREGNAME(1, Rn), SREGNAME(1, Rm)); } } OP4FUNC(op_pacda, z, m, Rn, Rd) { if (z != 0) { if (Rn != 31) { UNDEFINED(pc, insn, "undefined"); } else { PRINTF("%s\t%s\n", SHIFTOP2(m, "pacdza", "pacdzb"), SREGNAME(1, Rd)); } } else { PRINTF("%s\t%s, %s\n", SHIFTOP2(m, "pacda", "pacdb"), ZREGNAME(1, Rd), SREGNAME(1, Rn)); } } OP4FUNC(op_pacia, z, m, Rn, Rd) { if (z != 0) { if (Rn != 31) { UNDEFINED(pc, insn, "undefined"); } else { PRINTF("%s\t%s\n", SHIFTOP2(m, "paciza", "pacizb"), SREGNAME(1, Rd)); } } else { PRINTF("%s\t%s, %s\n", SHIFTOP2(m, "pacia", "pacib"), ZREGNAME(1, Rd), SREGNAME(1, Rn)); } } OP3FUNC(op_pacga, Rm, Rn, Rd) { PRINTF("pacga\t%s, %s, %s\n", ZREGNAME(1, Rd), ZREGNAME(1, Rn), SREGNAME(1, Rm)); } OP1FUNC(op_xpaci, Rd) { PRINTF("xpaci\t%s\n", ZREGNAME(1, Rd)); } OP1FUNC(op_xpacd, Rd) { PRINTF("xpacd\t%s\n", ZREGNAME(1, Rd)); } OP0FUNC(op_xpaclri) { PRINTF("xpaclri\n"); } /* * SIMD instructions are not supported except some insns. * They are disassembled as '.insn 0xXXXXXXXX'. */ struct bitpos { uint8_t pos; uint8_t width; }; struct insn_info { uint32_t mask; uint32_t pattern; #define INSN_MAXARG 8 struct bitpos bitinfo[INSN_MAXARG]; OPFUNC_DECL(void (*opfunc),,,,,,,,); }; /* define code format { {bitpos, bitwidth}, ... (maximum 8 args) } */ #define FMT_NOARG \ {{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RD \ {{ 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RN \ {{ 5, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RN_RT \ {{ 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_M \ {{10, 1}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_CRM \ {{ 8, 4}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_CRM_OP2 \ {{ 8, 4}, { 5, 3}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OP2_RN_RD \ {{10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_Z_M_RN_RD \ {{13, 1}, {10, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_M_D_RN_RD \ {{13, 1}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OP3_RN_RD \ {{12, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OP1_CRM_OP2 \ {{16, 3}, { 8, 4}, { 5, 3}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OP1_CRN_CRM_OP2_RT \ {{16, 3}, {12, 4}, { 8, 4}, { 5, 3}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RM_RN_RD \ {{16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RS_RN_RT \ {{16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RM_OP2_RN_RD \ {{16, 5}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RM_OP_RN_RD \ {{16, 5}, {12, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RM_RA_RN_RD \ {{16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMM9_RN_RT \ {{12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_RM_OPT_SHIFT_RN_RT \ {{16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMM16 \ {{ 5,16}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMM16_LL \ {{ 5,16}, { 0, 2}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OP0_OP1_CRN_CRM_OP2_RT \ {{19, 2}, {16, 3}, {12, 4}, { 8, 4}, { 5, 3}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_IMM7_RT2_RN_RT \ {{15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMM12_RN_RT \ {{10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OPC_IMM9_RN_RT \ {{22, 1}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OPC_RM_OPT_SHIFT_RN_RT \ {{22, 1}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_OPC_IMM12_RN_RT \ {{22, 1}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMM19_COND \ {{ 5,19}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMM19_RT \ {{ 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_Z_M_RN_RM \ {{24, 1}, {10, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMM26 \ {{ 0,26}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_RN_RT \ {{30, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_RT2_RN_RT \ {{30, 1}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_RS_RN_RT \ {{30, 1}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_RS_RT2_RN_RT \ {{30, 1}, {16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_IMM9_RN_RT \ {{30, 1}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_RM_OPT_SHIFT_RN_RT \ {{30, 1}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SIZE_IMM12_RN_RT \ {{30, 1}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_Q_SIZE_RM_RN_RD \ {{30, 1}, {22, 2}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_IMM19_RT \ {{30, 1}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_IMMLO_IMMHI_RD \ {{29, 2}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_RN_RD \ {{31, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_OPC_RN_RD \ {{31, 1}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_RM_RN_RD \ {{31, 1}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_RM_SZ_RN_RD \ {{31, 1}, {16, 5}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_RM_RA_RN_RD \ {{31, 1}, {16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_IMM5_COND_RN_NZCV \ {{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_RM_COND_RN_NZCV \ {{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_RM_COND_RN_RD \ {{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_RM_OPT_IMM3_RN_RD \ {{31, 1}, {16, 5}, {13, 3}, {10, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SF_RM_OP_IMM3_RN_RD \ {{31, 1}, {16, 5}, {13, 3}, {10, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SF_IMM7_RT2_RN_RT \ {{31, 1}, {15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_N_RM_IMM6_RN_RD \ {{31, 1}, {22, 1}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SF_N_RM_IMMS_RN_RD \ {{31, 1}, {22, 1}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SF_HW_IMM16_RD \ {{31, 1}, {21, 2}, { 5,16}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_N_IMMR_IMMS_RN_RD \ {{31, 1}, {22, 1}, {16, 6}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SF_SHIFT_RM_IMM6_RN_RD \ {{31, 1}, {22, 2}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SF_SHIFT_IMM12_RN_RD \ {{31, 1}, {22, 2}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SF_IMM19_RT \ {{31, 1}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_B5_B40_IMM14_RT \ {{31, 1}, {19, 5}, { 5,14}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_OPC_L_IMM7_RT2_RN_RT \ {{30, 2}, {22, 1}, {15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}} #define FMT_SIZE_OPC_IMM9_RN_RT \ {{30, 2}, {22, 2}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} #define FMT_SIZE_OPC_RM_OPT_S_RN_RT \ {{30, 2}, {22, 2}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}} #define FMT_SIZE_OPC_IMM12_RN_RT \ {{30, 2}, {22, 2}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}} static const struct insn_info insn_tables[] = { /* mask, pattern, opcode format, opfunc */ /* --------- ---------- --------------------------- ------------------ */ { 0xffffffff, 0xd6bf03e0, FMT_NOARG, op_drps }, { 0xffffffff, 0xd69f03e0, FMT_NOARG, op_eret }, { 0xffffffff, 0xd50320ff, FMT_NOARG, op_xpaclri }, { 0xffffffe0, 0xdac143e0, FMT_RD, op_xpaci }, { 0xffffffe0, 0xdac147e0, FMT_RD, op_xpacd }, { 0xfffffc1f, 0xd63f0000, FMT_RN, op_blr }, { 0xfffffc1f, 0xd61f0000, FMT_RN, op_br }, { 0xfffffc1f, 0xd65f0000, FMT_RN, op_ret }, { 0xfffffc00, 0x08dffc00, FMT_RN_RT, op_ldarb }, { 0xfffffc00, 0x48dffc00, FMT_RN_RT, op_ldarh }, { 0xfffffc00, 0x085ffc00, FMT_RN_RT, op_ldaxrb }, { 0xfffffc00, 0x485ffc00, FMT_RN_RT, op_ldaxrh }, { 0xfffffc00, 0x085f7c00, FMT_RN_RT, op_ldxrb }, { 0xfffffc00, 0x485f7c00, FMT_RN_RT, op_ldxrh }, { 0xfffffc00, 0x089ffc00, FMT_RN_RT, op_stlrb }, { 0xfffffc00, 0x489ffc00, FMT_RN_RT, op_stlrh }, { 0xfffffbff, 0xd69f0bff, FMT_M, op_eretaa }, { 0xfffffbff, 0xd65f0bff, FMT_M, op_retaa }, { 0xfffff0ff, 0xd503305f, FMT_CRM, op_clrex }, { 0xfffff0ff, 0xd50330bf, FMT_CRM, op_dmb }, { 0xfffff0ff, 0xd503309f, FMT_CRM, op_dsb }, { 0xfffff0ff, 0xd50330df, FMT_CRM, op_isb }, { 0xfffff01f, 0xd503201f, FMT_CRM_OP2, op_hint }, { 0xfffff000, 0xcec08000, FMT_OP2_RN_RD, op_simd_sha512_reg2 }, { 0xffffd800, 0xdac10800, FMT_Z_M_RN_RD, op_pacda }, { 0xffffd800, 0xdac10000, FMT_Z_M_RN_RD, op_pacia }, { 0xffffcc00, 0x4e284800, FMT_M_D_RN_RD, op_simd_aes }, { 0xffff8c00, 0x5e280800, FMT_OP3_RN_RD, op_simd_sha_reg2 }, { 0xfff8f01f, 0xd500401f, FMT_OP1_CRM_OP2, op_msr_imm }, { 0xfff80000, 0xd5080000, FMT_OP1_CRN_CRM_OP2_RT, op_sys }, { 0xfff80000, 0xd5280000, FMT_OP1_CRN_CRM_OP2_RT, op_sysl }, { 0xffe0fc00, 0x9b407c00, FMT_RM_RN_RD, op_smulh }, { 0xffe0fc00, 0x0800fc00, FMT_RS_RN_RT, op_stlxrb }, { 0xffe0fc00, 0x4800fc00, FMT_RS_RN_RT, op_stlxrh }, { 0xffe0fc00, 0x08007c00, FMT_RS_RN_RT, op_stxrb }, { 0xffe0fc00, 0x48007c00, FMT_RS_RN_RT, op_stxrh }, { 0xffe0fc00, 0x9bc07c00, FMT_RM_RN_RD, op_umulh }, { 0xffe0fc00, 0x9ac03000, FMT_RM_RN_RD, op_pacga }, { 0xffe0f000, 0xce608000, FMT_RM_OP2_RN_RD, op_simd_sha512_reg3 }, { 0xffe08c00, 0x5e000000, FMT_RM_OP_RN_RD, op_simd_sha_reg3 }, { 0xffe08000, 0x9b208000, FMT_RM_RA_RN_RD, op_smsubl }, { 0xffe08000, 0x9ba08000, FMT_RM_RA_RN_RD, op_umsubl }, { 0xffe08000, 0x9b200000, FMT_RM_RA_RN_RD, op_smaddl }, { 0xffe08000, 0x9ba00000, FMT_RM_RA_RN_RD, op_umaddl }, { 0xffe00c00, 0x38400400, FMT_IMM9_RN_RT, op_ldrb_immpostidx }, { 0xffe00c00, 0x38400c00, FMT_IMM9_RN_RT, op_ldrb_immpreidx }, { 0xffe00c00, 0x38600800, FMT_RM_OPT_SHIFT_RN_RT, op_ldrb_reg }, { 0xffe00c00, 0x78400400, FMT_IMM9_RN_RT, op_ldrh_immpostidx }, { 0xffe00c00, 0x78400c00, FMT_IMM9_RN_RT, op_ldrh_immpreidx }, { 0xffe00c00, 0x78600800, FMT_RM_OPT_SHIFT_RN_RT, op_ldrh_reg }, { 0xffe00c00, 0xb8800400, FMT_IMM9_RN_RT, op_ldrsw_immpostidx }, { 0xffe00c00, 0xb8800c00, FMT_IMM9_RN_RT, op_ldrsw_immpreidx }, { 0xffe00c00, 0xb8a00800, FMT_RM_OPT_SHIFT_RN_RT, op_ldrsw_reg }, { 0xffe00c00, 0x38400800, FMT_IMM9_RN_RT, op_ldtrb }, { 0xffe00c00, 0x78400800, FMT_IMM9_RN_RT, op_ldtrh }, { 0xffe00c00, 0xb8800800, FMT_IMM9_RN_RT, op_ldtrsw }, { 0xffe00c00, 0x38400000, FMT_IMM9_RN_RT, op_ldurb }, { 0xffe00c00, 0x78400000, FMT_IMM9_RN_RT, op_ldurh }, { 0xffe00c00, 0xb8800000, FMT_IMM9_RN_RT, op_ldursw }, { 0xffe00c00, 0xf8a00800, FMT_RM_OPT_SHIFT_RN_RT, op_prfm_reg }, { 0xffe00c00, 0xf8800000, FMT_IMM9_RN_RT, op_prfum }, { 0xffe00c00, 0x38000400, FMT_IMM9_RN_RT, op_strb_immpostidx }, { 0xffe00c00, 0x38000c00, FMT_IMM9_RN_RT, op_strb_immpreidx }, { 0xffe00c00, 0x38200800, FMT_RM_OPT_SHIFT_RN_RT, op_strb_reg }, { 0xffe00c00, 0x78000400, FMT_IMM9_RN_RT, op_strh_immpostidx }, { 0xffe00c00, 0x78000c00, FMT_IMM9_RN_RT, op_strh_immpreidx }, { 0xffe00c00, 0x78200800, FMT_RM_OPT_SHIFT_RN_RT, op_strh_reg }, { 0xffe00c00, 0x38000800, FMT_IMM9_RN_RT, op_sttrb }, { 0xffe00c00, 0x78000800, FMT_IMM9_RN_RT, op_sttrh }, { 0xffe00c00, 0x38000000, FMT_IMM9_RN_RT, op_sturb }, { 0xffe00c00, 0x78000000, FMT_IMM9_RN_RT, op_sturh }, { 0xffe0001f, 0xd4200000, FMT_IMM16, op_brk }, { 0xffe0001f, 0xd4400000, FMT_IMM16, op_hlt }, { 0xffe0001f, 0xd4000002, FMT_IMM16, op_hvc }, { 0xffe0001f, 0xd4000003, FMT_IMM16, op_smc }, { 0xffe0001f, 0xd4000001, FMT_IMM16, op_svc }, { 0xffe0001c, 0xd4a00000, FMT_IMM16_LL, op_dcps }, { 0xffe00000, 0xd5200000, FMT_OP0_OP1_CRN_CRM_OP2_RT, op_mrs }, { 0xffe00000, 0xd5000000, FMT_OP0_OP1_CRN_CRM_OP2_RT, op_msr }, { 0xffc00000, 0x68c00000, FMT_IMM7_RT2_RN_RT, op_ldpsw_postidx }, { 0xffc00000, 0x69c00000, FMT_IMM7_RT2_RN_RT, op_ldpsw_preidx }, { 0xffc00000, 0x69400000, FMT_IMM7_RT2_RN_RT, op_ldpsw_signed }, { 0xffc00000, 0x39400000, FMT_IMM12_RN_RT, op_ldrb_immunsign }, { 0xffc00000, 0x79400000, FMT_IMM12_RN_RT, op_ldrh_immunsign }, { 0xffc00000, 0xb9800000, FMT_IMM12_RN_RT, op_ldrsw_immunsign }, { 0xffc00000, 0xf9800000, FMT_IMM12_RN_RT, op_prfm_imm }, { 0xffc00000, 0x39000000, FMT_IMM12_RN_RT, op_strb_immunsign }, { 0xffc00000, 0x79000000, FMT_IMM12_RN_RT, op_strh_immunsign }, { 0xffa00c00, 0x38800400, FMT_OPC_IMM9_RN_RT, op_ldrsb_immpostidx }, { 0xffa00c00, 0x38800c00, FMT_OPC_IMM9_RN_RT, op_ldrsb_immpreidx }, { 0xffa00c00, 0x38a00800, FMT_OPC_RM_OPT_SHIFT_RN_RT, op_ldrsb_reg }, { 0xffa00c00, 0x78800400, FMT_OPC_IMM9_RN_RT, op_ldrsh_immpostidx }, { 0xffa00c00, 0x78800c00, FMT_OPC_IMM9_RN_RT, op_ldrsh_immpreidx }, { 0xffa00c00, 0x78a00800, FMT_OPC_RM_OPT_SHIFT_RN_RT, op_ldrsh_reg }, { 0xffa00c00, 0x38800800, FMT_OPC_IMM9_RN_RT, op_ldtrsb }, { 0xffa00c00, 0x78800800, FMT_OPC_IMM9_RN_RT, op_ldtrsh }, { 0xffa00c00, 0x38800000, FMT_OPC_IMM9_RN_RT, op_ldursb }, { 0xffa00c00, 0x78800000, FMT_OPC_IMM9_RN_RT, op_ldursh }, { 0xff800000, 0x39800000, FMT_OPC_IMM12_RN_RT, op_ldrsb_immunsign }, { 0xff800000, 0x79800000, FMT_OPC_IMM12_RN_RT, op_ldrsh_immunsign }, { 0xff000010, 0x54000000, FMT_IMM19_COND, op_b_cond }, { 0xff000000, 0x98000000, FMT_IMM19_RT, op_ldrsw_literal }, { 0xff000000, 0xd8000000, FMT_IMM19_RT, op_prfm_literal }, { 0xfefff800, 0xd63f0800, FMT_Z_M_RN_RM, op_blraa }, { 0xfefff800, 0xd61f0800, FMT_Z_M_RN_RM, op_braa }, { 0xfc000000, 0x14000000, FMT_IMM26, op_b }, { 0xfc000000, 0x94000000, FMT_IMM26, op_bl }, { 0xbffffc00, 0x88dffc00, FMT_SIZE_RN_RT, op_ldar }, { 0xbffffc00, 0x885ffc00, FMT_SIZE_RN_RT, op_ldaxr }, { 0xbffffc00, 0x885f7c00, FMT_SIZE_RN_RT, op_ldxr }, { 0xbffffc00, 0x889ffc00, FMT_SIZE_RN_RT, op_stlr }, { 0xbfff8000, 0x887f8000, FMT_SIZE_RT2_RN_RT, op_ldaxp }, { 0xbfff8000, 0x887f0000, FMT_SIZE_RT2_RN_RT, op_ldxp }, { 0xbfe0fc00, 0x8800fc00, FMT_SIZE_RS_RN_RT, op_stlxr }, { 0xbfe0fc00, 0x88007c00, FMT_SIZE_RS_RN_RT, op_stxr }, { 0xbfe08000, 0x88208000, FMT_SIZE_RS_RT2_RN_RT, op_stlxp }, { 0xbfe08000, 0x88200000, FMT_SIZE_RS_RT2_RN_RT, op_stxp }, { 0xbfe00c00, 0xb8400400, FMT_SIZE_IMM9_RN_RT, op_ldr_immpostidx }, { 0xbfe00c00, 0xb8400c00, FMT_SIZE_IMM9_RN_RT, op_ldr_immpreidx }, { 0xbfe00c00, 0xb8600800, FMT_SIZE_RM_OPT_SHIFT_RN_RT, op_ldr_reg }, { 0xbfe00c00, 0xb8400800, FMT_SIZE_IMM9_RN_RT, op_ldtr }, { 0xbfe00c00, 0xb8400000, FMT_SIZE_IMM9_RN_RT, op_ldur }, { 0xbfe00c00, 0xb8000400, FMT_SIZE_IMM9_RN_RT, op_str_immpostidx }, { 0xbfe00c00, 0xb8000c00, FMT_SIZE_IMM9_RN_RT, op_str_immpreidx }, { 0xbfe00c00, 0xb8200800, FMT_SIZE_RM_OPT_SHIFT_RN_RT, op_str_reg }, { 0xbfe00c00, 0xb8000800, FMT_SIZE_IMM9_RN_RT, op_sttr }, { 0xbfe00c00, 0xb8000000, FMT_SIZE_IMM9_RN_RT, op_stur }, { 0xbfc00000, 0xb9400000, FMT_SIZE_IMM12_RN_RT, op_ldr_immunsign }, { 0xbfc00000, 0xb9000000, FMT_SIZE_IMM12_RN_RT, op_str_immunsign }, { 0xbf20fc00, 0x0e20e000, FMT_Q_SIZE_RM_RN_RD, op_simd_pmull }, { 0xbf000000, 0x18000000, FMT_SIZE_IMM19_RT, op_ldr_literal }, { 0x9f000000, 0x10000000, FMT_IMMLO_IMMHI_RD, op_adr }, { 0x9f000000, 0x90000000, FMT_IMMLO_IMMHI_RD, op_adrp }, { 0x7ffffc00, 0x5ac01400, FMT_SF_RN_RD, op_cls }, { 0x7ffffc00, 0x5ac01000, FMT_SF_RN_RD, op_clz }, { 0x7ffff000, 0x5ac00000, FMT_SF_OPC_RN_RD, op_rev }, { 0x7fe0fc00, 0x5a000000, FMT_SF_RM_RN_RD, op_sbc }, { 0x7fe0fc00, 0x7a000000, FMT_SF_RM_RN_RD, op_sbcs }, { 0x7fe0fc00, 0x1a000000, FMT_SF_RM_RN_RD, op_adc }, { 0x7fe0fc00, 0x3a000000, FMT_SF_RM_RN_RD, op_adcs }, { 0x7fe0fc00, 0x1ac02800, FMT_SF_RM_RN_RD, op_asr_reg }, { 0x7fe0fc00, 0x1ac02000, FMT_SF_RM_RN_RD, op_lsl_reg }, { 0x7fe0fc00, 0x1ac02400, FMT_SF_RM_RN_RD, op_lsr_reg }, { 0x7fe0fc00, 0x1ac02c00, FMT_SF_RM_RN_RD, op_ror_reg }, { 0x7fe0fc00, 0x1ac00c00, FMT_SF_RM_RN_RD, op_sdiv }, { 0x7fe0fc00, 0x1ac00800, FMT_SF_RM_RN_RD, op_udiv }, { 0x7fe0f000, 0x1ac04000, FMT_SF_RM_SZ_RN_RD, op_crc32 }, { 0x7fe0f000, 0x1ac05000, FMT_SF_RM_SZ_RN_RD, op_crc32c }, { 0x7fe08000, 0x1b008000, FMT_SF_RM_RA_RN_RD, op_msub }, { 0x7fe08000, 0x1b000000, FMT_SF_RM_RA_RN_RD, op_madd }, { 0x7fe00c10, 0x3a400800, FMT_SF_IMM5_COND_RN_NZCV, op_ccmn_imm }, { 0x7fe00c10, 0x3a400000, FMT_SF_RM_COND_RN_NZCV, op_ccmn_reg }, { 0x7fe00c10, 0x7a400800, FMT_SF_IMM5_COND_RN_NZCV, op_ccmp_imm }, { 0x7fe00c10, 0x7a400000, FMT_SF_RM_COND_RN_NZCV, op_ccmp_reg }, { 0x7fe00c00, 0x5a800000, FMT_SF_RM_COND_RN_RD, op_csinv }, { 0x7fe00c00, 0x5a800400, FMT_SF_RM_COND_RN_RD, op_csneg }, { 0x7fe00c00, 0x1a800400, FMT_SF_RM_COND_RN_RD, op_cinc }, { 0x7fe00c00, 0x1a800000, FMT_SF_RM_COND_RN_RD, op_csel }, { 0x7fe00000, 0x6b200000, FMT_SF_RM_OPT_IMM3_RN_RD, op_subs_extreg }, { 0x7fe00000, 0x0b200000, FMT_SF_RM_OPT_IMM3_RN_RD, op_add_extreg }, { 0x7fe00000, 0x2b200000, FMT_SF_RM_OP_IMM3_RN_RD, op_adds_extreg }, { 0x7fe00000, 0x4b200000, FMT_SF_RM_OPT_IMM3_RN_RD, op_sub_extreg }, { 0x7fc00000, 0x28400000, FMT_SF_IMM7_RT2_RN_RT, op_ldnp }, { 0x7fc00000, 0x28c00000, FMT_SF_IMM7_RT2_RN_RT, op_ldp_postidx }, { 0x7fc00000, 0x29c00000, FMT_SF_IMM7_RT2_RN_RT, op_ldp_preidx }, { 0x7fc00000, 0x29400000, FMT_SF_IMM7_RT2_RN_RT, op_ldp_signed }, { 0x7fc00000, 0x28000000, FMT_SF_IMM7_RT2_RN_RT, op_stnp }, { 0x7fc00000, 0x28800000, FMT_SF_IMM7_RT2_RN_RT, op_stp_postidx }, { 0x7fc00000, 0x29800000, FMT_SF_IMM7_RT2_RN_RT, op_stp_preidx }, { 0x7fc00000, 0x29000000, FMT_SF_IMM7_RT2_RN_RT, op_stp_signed }, { 0x7fa00000, 0x13800000, FMT_SF_N_RM_IMM6_RN_RD, op_ror_imm }, { 0x7f800000, 0x12800000, FMT_SF_HW_IMM16_RD, op_movn }, { 0x7f800000, 0x52800000, FMT_SF_HW_IMM16_RD, op_movz }, { 0x7f800000, 0x32000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_orr_imm }, { 0x7f800000, 0x13000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_sbfm }, { 0x7f800000, 0x53000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_ubfm }, { 0x7f800000, 0x12000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_and_imm }, { 0x7f800000, 0x72000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_ands_imm }, { 0x7f800000, 0x33000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_bfi }, { 0x7f800000, 0x52000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_eor_imm }, { 0x7f800000, 0x72800000, FMT_SF_HW_IMM16_RD, op_movk }, { 0x7f200000, 0x2a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_orn }, { 0x7f200000, 0x2a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_orr_reg }, { 0x7f200000, 0x4b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_sub_shiftreg }, { 0x7f200000, 0x6b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_subs_shiftreg }, { 0x7f200000, 0x0b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_add_shiftreg }, { 0x7f200000, 0x2b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_adds_shiftreg }, { 0x7f200000, 0x0a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_and_shiftreg }, { 0x7f200000, 0x6a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_ands_shiftreg }, { 0x7f200000, 0x0a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_bic_shiftreg }, { 0x7f200000, 0x6a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_bics_shiftreg }, { 0x7f200000, 0x4a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_eon_shiftreg }, { 0x7f200000, 0x4a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_eor_shiftreg }, { 0x7f000000, 0x71000000, FMT_SF_SHIFT_IMM12_RN_RD, op_subs_imm }, { 0x7f000000, 0x11000000, FMT_SF_SHIFT_IMM12_RN_RD, op_add_imm }, { 0x7f000000, 0x31000000, FMT_SF_SHIFT_IMM12_RN_RD, op_adds_imm }, { 0x7f000000, 0x35000000, FMT_SF_IMM19_RT, op_cbnz }, { 0x7f000000, 0x34000000, FMT_SF_IMM19_RT, op_cbz }, { 0x7f000000, 0x51000000, FMT_SF_SHIFT_IMM12_RN_RD, op_sub_imm }, { 0x7f000000, 0x37000000, FMT_B5_B40_IMM14_RT, op_tbnz }, { 0x7f000000, 0x36000000, FMT_B5_B40_IMM14_RT, op_tbz }, { 0x3f800000, 0x2c000000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstnp }, { 0x3f800000, 0x2c800000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstp_postidx }, { 0x3f800000, 0x2d800000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstp_preidx }, { 0x3f800000, 0x2d000000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstp_signed }, { 0x3f200c00, 0x3c000400, FMT_SIZE_OPC_IMM9_RN_RT, op_simd_ldstr_immpostidx }, { 0x3f200c00, 0x3c000c00, FMT_SIZE_OPC_IMM9_RN_RT, op_simd_ldstr_immpreidx }, { 0x3f200c00, 0x3c200800, FMT_SIZE_OPC_RM_OPT_S_RN_RT, op_simd_ldstr_reg }, { 0x3f000000, 0x3d000000, FMT_SIZE_OPC_IMM12_RN_RT, op_simd_ldstr_immunsign }, { 0x00000000, 0x00000000, FMT_NOARG, op_undefined } }; #define WIDTHMASK(w) (0xffffffff >> (32 - (w))) void disasm_insn(const disasm_interface_t *di, uintptr_t loc, uint32_t insn) { uint64_t args[INSN_MAXARG]; unsigned int i, j; for (i = 0; i < __arraycount(insn_tables); i++) { if ((insn & insn_tables[i].mask) != insn_tables[i].pattern) continue; /* extract operands */ for (j = 0; j < INSN_MAXARG; j++) { if (insn_tables[i].bitinfo[j].width == 0) break; args[j] = (insn >> insn_tables[i].bitinfo[j].pos) & WIDTHMASK(insn_tables[i].bitinfo[j].width); } insn_tables[i].opfunc(di, loc, insn, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break; } } uintptr_t disasm(const disasm_interface_t *di, uintptr_t loc) { uint32_t insn; insn = le32toh(di->di_readword(loc)); disasm_insn(di, loc, insn); /* return next address */ return loc + sizeof(insn); }