diff --git a/build.bat b/build.bat index 5c84db91e..70d75721f 100644 --- a/build.bat +++ b/build.bat @@ -29,6 +29,7 @@ cd /D "%~dp0" for %%a in (%*) do set "%%a=1" if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1 if not "%release%"=="1" set debug=1 +if not "%arm64%"=="1" set x64=1 if "%debug%"=="1" set release=0 && echo [debug mode] if "%release%"=="1" set debug=0 && echo [release mode] if "%msvc%"=="1" set clang=0 && echo [msvc compile] @@ -64,10 +65,11 @@ if "%msvc%"=="1" set only_compile=/c if "%clang%"=="1" set only_compile=-c if "%msvc%"=="1" set EHsc=/EHsc if "%clang%"=="1" set EHsc= -if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO -if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO +if "%msvc%"=="1" if "%x64%"=="1" set no_aslr=/DYNAMICBASE:NO +if "%clang%"=="1" if "%x64%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO if "%msvc%"=="1" set rc=call rc if "%clang%"=="1" set rc=call llvm-rc +if "%arm64%"=="1" set no_aslr= :: --- Choose Compile/Link Lines ---------------------------------------------- if "%msvc%"=="1" set compile_debug=%cl_debug% diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h index bac701dd3..525364ed2 100644 --- a/src/base/base_context_cracking.h +++ b/src/base/base_context_cracking.h @@ -72,6 +72,7 @@ # define ARCH_X86 1 # elif defined(_M_ARM64) # define ARCH_ARM64 1 +# define USE_SOFT_INTRINSICS # elif defined(_M_ARM) # define ARCH_ARM32 1 # else @@ -110,7 +111,7 @@ //////////////////////////////// //~ rjf: Arch Cracking -#if defined(ARCH_X64) +#if defined(ARCH_X64) || defined(ARCH_ARM64) # define ARCH_64BIT 1 #elif defined(ARCH_X86) # define ARCH_32BIT 1 @@ -238,10 +239,13 @@ //~ rjf: Unsupported Errors #if ARCH_X86 -# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported. +# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 and arm64 (64 bit) mode is supported. #endif -#if !ARCH_X64 -# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported. +#if ARCH_ARM32 +# error You tried to build in arm32 (32 bit) mode, but currently, only building in x64 and arm64 (64 bit) mode is supported. +#endif +#if !defined(ARCH_X64) || !defined(ARCH_ARM64) +# error You tried to build with an unsupported architecture. Currently, only building in x64 and arm64 mode is supported. #endif #endif // BASE_CONTEXT_CRACKING_H diff --git a/src/base/base_core.h b/src/base/base_core.h index 191e1e7f4..b4e22c3ae 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -180,7 +180,7 @@ #if COMPILER_MSVC # include -# if ARCH_X64 +# if defined(ARCH_X64) || defined(ARCH_ARM64) # define ins_atomic_u64_eval(x) *((volatile U64 *)(x)) # define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x)) # define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x)) diff --git a/src/base/base_strings.h b/src/base/base_strings.h index fc946dd8a..bafba22b7 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -8,6 +8,9 @@ //~ rjf: Third Party Includes #define STB_SPRINTF_DECORATE(name) raddbg_##name +#if ARCH_64BIT +#define stbsp__uintptr U64 +#endif #include "third_party/stb/stb_sprintf.h" //////////////////////////////// diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index 2ac3aecec..d7ae4321a 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -1013,6 +1013,181 @@ typedef enum CV_Regx64Enum } CV_Regx64Enum; +// X(NAME, CODE, (RDI_RegisterCode_ARM64) NAME, BYTE_POS, BYTE_SIZE) +#define CV_Reg_ARM64_XList(X) \ +X(NONE, 0, nil, 0, 0)\ +X(W0, 10, x0, 0, 4)\ +X(W1, 11, x1, 0, 4)\ +X(W2, 12, x2, 0, 4)\ +X(W3, 13, x3, 0, 4)\ +X(W4, 14, x4, 0, 4)\ +X(W5, 15, x5, 0, 4)\ +X(W6, 16, x6, 0, 4)\ +X(W7, 17, x7, 0, 4)\ +X(W8, 18, x8, 0, 4)\ +X(W9, 19, x9, 0, 4)\ +X(W10, 20, x10, 0, 4)\ +X(W11, 21, x11, 0, 4)\ +X(W12, 22, x12, 0, 4)\ +X(W13, 23, x13, 0, 4)\ +X(W14, 24, x14, 0, 4)\ +X(W15, 25, x15, 0, 4)\ +X(W16, 26, x16, 0, 4)\ +X(W17, 27, x17, 0, 4)\ +X(W18, 28, x18, 0, 4)\ +X(W19, 29, x19, 0, 4)\ +X(W20, 30, x20, 0, 4)\ +X(W21, 31, x21, 0, 4)\ +X(W22, 32, x22, 0, 4)\ +X(W23, 33, x23, 0, 4)\ +X(W24, 34, x24, 0, 4)\ +X(W25, 35, x25, 0, 4)\ +X(W26, 36, x26, 0, 4)\ +X(W27, 37, x27, 0, 4)\ +X(W28, 38, x28, 0, 4)\ +X(W29, 39, x29, 0, 4)\ +X(W30, 40, x30, 0, 4)\ +X(WZR, 41, x31, 0, 4)\ +X(X0, 50, x0, 0, 8)\ +X(X1, 51, x1, 0, 8)\ +X(X2, 52, x2, 0, 8)\ +X(X3, 53, x3, 0, 8)\ +X(X4, 54, x4, 0, 8)\ +X(X5, 55, x5, 0, 8)\ +X(X6, 56, x6, 0, 8)\ +X(X7, 57, x7, 0, 8)\ +X(X8, 58, x8, 0, 8)\ +X(X9, 59, x9, 0, 8)\ +X(X10, 60, x10, 0, 8)\ +X(X11, 61, x11, 0, 8)\ +X(X12, 62, x12, 0, 8)\ +X(X13, 63, x13, 0, 8)\ +X(X14, 64, x14, 0, 8)\ +X(X15, 65, x15, 0, 8)\ +X(IP0, 66, x16, 0, 8)\ +X(IP1, 67, x17, 0, 8)\ +X(X18, 68, x18, 0, 8)\ +X(X19, 69, x19, 0, 8)\ +X(X20, 70, x20, 0, 8)\ +X(X21, 71, x21, 0, 8)\ +X(X22, 72, x22, 0, 8)\ +X(X23, 73, x23, 0, 8)\ +X(X24, 74, x24, 0, 8)\ +X(X25, 75, x25, 0, 8)\ +X(X26, 76, x26, 0, 8)\ +X(X27, 77, x27, 0, 8)\ +X(X28, 78, x28, 0, 8)\ +X(FP, 79, x29, 0, 8)\ +X(LR, 80, x30, 0, 8)\ +X(SP, 81, x31, 0, 8)\ +X(ZR, 82, x31, 0, 8)\ +X(NZCV, 90, context_flags, 0, 4)\ +X(S0, 100, v0, 0, 4)\ +X(S1, 101, v1, 0, 4)\ +X(S2, 102, v2, 0, 4)\ +X(S3, 103, v3, 0, 4)\ +X(S4, 104, v4, 0, 4)\ +X(S5, 105, v5, 0, 4)\ +X(S6, 106, v6, 0, 4)\ +X(S7, 107, v7, 0, 4)\ +X(S8, 108, v8, 0, 4)\ +X(S9, 109, v9, 0, 4)\ +X(S10, 110, v10, 0, 4)\ +X(S11, 111, v11, 0, 4)\ +X(S12, 112, v12, 0, 4)\ +X(S13, 113, v13, 0, 4)\ +X(S14, 114, v14, 0, 4)\ +X(S15, 115, v15, 0, 4)\ +X(S16, 116, v16, 0, 4)\ +X(S17, 117, v17, 0, 4)\ +X(S18, 118, v18, 0, 4)\ +X(S19, 119, v19, 0, 4)\ +X(S20, 120, v20, 0, 4)\ +X(S21, 121, v21, 0, 4)\ +X(S22, 122, v22, 0, 4)\ +X(S23, 123, v23, 0, 4)\ +X(S24, 124, v24, 0, 4)\ +X(S25, 125, v25, 0, 4)\ +X(S26, 126, v26, 0, 4)\ +X(S27, 127, v27, 0, 4)\ +X(S28, 128, v28, 0, 4)\ +X(S29, 129, v29, 0, 4)\ +X(S30, 130, v30, 0, 4)\ +X(S31, 131, v31, 0, 4)\ +X(D0, 140, v0, 0, 8)\ +X(D1, 141, v1, 0, 8)\ +X(D2, 142, v2, 0, 8)\ +X(D3, 143, v3, 0, 8)\ +X(D4, 144, v4, 0, 8)\ +X(D5, 145, v5, 0, 8)\ +X(D6, 146, v6, 0, 8)\ +X(D7, 147, v7, 0, 8)\ +X(D8, 148, v8, 0, 8)\ +X(D9, 149, v9, 0, 8)\ +X(D10, 150, v10, 0, 8)\ +X(D11, 151, v11, 0, 8)\ +X(D12, 152, v12, 0, 8)\ +X(D13, 153, v13, 0, 8)\ +X(D14, 154, v14, 0, 8)\ +X(D15, 155, v15, 0, 8)\ +X(D16, 156, v16, 0, 8)\ +X(D17, 157, v17, 0, 8)\ +X(D18, 158, v18, 0, 8)\ +X(D19, 159, v19, 0, 8)\ +X(D20, 160, v20, 0, 8)\ +X(D21, 161, v21, 0, 8)\ +X(D22, 162, v22, 0, 8)\ +X(D23, 163, v23, 0, 8)\ +X(D24, 164, v24, 0, 8)\ +X(D25, 165, v25, 0, 8)\ +X(D26, 166, v26, 0, 8)\ +X(D27, 167, v27, 0, 8)\ +X(D28, 168, v28, 0, 8)\ +X(D29, 169, v29, 0, 8)\ +X(D30, 170, v30, 0, 8)\ +X(D31, 171, v31, 0, 8)\ +X(Q0, 180, v0, 0, 16)\ +X(Q1, 181, v1, 0, 16)\ +X(Q2, 182, v2, 0, 16)\ +X(Q3, 183, v3, 0, 16)\ +X(Q4, 184, v4, 0, 16)\ +X(Q5, 185, v5, 0, 16)\ +X(Q6, 186, v6, 0, 16)\ +X(Q7, 187, v7, 0, 16)\ +X(Q8, 188, v8, 0, 16)\ +X(Q9, 189, v9, 0, 16)\ +X(Q10, 190, v10, 0, 16)\ +X(Q11, 191, v11, 0, 16)\ +X(Q12, 192, v12, 0, 16)\ +X(Q13, 193, v13, 0, 16)\ +X(Q14, 194, v14, 0, 16)\ +X(Q15, 195, v15, 0, 16)\ +X(Q16, 196, v16, 0, 16)\ +X(Q17, 197, v17, 0, 16)\ +X(Q18, 198, v18, 0, 16)\ +X(Q19, 199, v19, 0, 16)\ +X(Q20, 200, v20, 0, 16)\ +X(Q21, 201, v21, 0, 16)\ +X(Q22, 202, v22, 0, 16)\ +X(Q23, 203, v23, 0, 16)\ +X(Q24, 204, v24, 0, 16)\ +X(Q25, 205, v25, 0, 16)\ +X(Q26, 206, v26, 0, 16)\ +X(Q27, 207, v27, 0, 16)\ +X(Q28, 208, v28, 0, 16)\ +X(Q29, 209, v29, 0, 16)\ +X(Q30, 210, v30, 0, 16)\ +X(Q31, 211, v31, 0, 16)\ +X(FPSR, 220, fpsr, 0, 4) + +typedef U16 CV_Regarm64; +typedef enum CV_Regarm64Enum +{ +#define X(CVN,C,RDN,BP,BZ) CV_Regarm64_##CVN = C, + CV_Reg_ARM64_XList(X) +#undef X +} +CV_Regarm64Enum; #define CV_SignatureXList(X) \ X(C6, 0) \ diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 410120338..bf071bf26 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1908,9 +1908,9 @@ ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_Handle module_handle, U64 v { if(ctrl_handle_match(n->module, module_handle)) { - PE_IntelPdata *pdatas = n->pdatas; - U64 pdatas_count = n->pdatas_count; - if(n->pdatas_count != 0 && voff >= n->pdatas[0].voff_first) + PE_IntelPdata *pdatas = n->intel_pdatas; + U64 pdatas_count = n->intel_pdatas_count; + if(n->intel_pdatas_count != 0 && voff >= n->intel_pdatas[0].voff_first) { // NOTE(rjf): // @@ -2537,7 +2537,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U64 frame_off = 0; { U64 unwind_info_off = first_pdata->voff_unwind_info; - PE_UnwindInfo unwind_info = {0}; + PE_UnwindInfoX64 unwind_info = {0}; if(!ctrl_read_cached_process_memory_struct(process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us) || is_stale) { @@ -2561,11 +2561,11 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT //- rjf: unpack unwind info & codes B32 good_unwind_info = 1; U64 unwind_info_off = pdata->voff_unwind_info; - PE_UnwindInfo unwind_info = {0}; + PE_UnwindInfoX64 unwind_info = {0}; good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory_struct(process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); - PE_UnwindCode *unwind_codes = push_array(scratch.arena, PE_UnwindCode, unwind_info.codes_num); + PE_UnwindCodeX64 *unwind_codes = push_array(scratch.arena, PE_UnwindCodeX64, unwind_info.codes_num); good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory(process->handle, r1u64(module->vaddr_range.min+unwind_info_off+sizeof(unwind_info), - module->vaddr_range.min+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num), + module->vaddr_range.min+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCodeX64)*unwind_info.codes_num), &is_stale, unwind_codes, endt_us); good_unwind_info = good_unwind_info && !is_stale; @@ -2586,15 +2586,15 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT } //- rjf: apply opcodes - PE_UnwindCode *code_ptr = unwind_codes; - PE_UnwindCode *code_opl = unwind_codes + unwind_info.codes_num; - for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) + PE_UnwindCodeX64 *code_ptr = unwind_codes; + PE_UnwindCodeX64 *code_opl = unwind_codes + unwind_info.codes_num; + for(PE_UnwindCodeX64 *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) { // rjf: unpack opcode info U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); - U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); - if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) + U32 slot_count = pe_slot_count_from_unwind_op_code__x64(op_code); + if(op_code == PE_UnwindOpCodeX64_ALLOC_LARGE && op_info == 1) { slot_count += 1; } @@ -2616,7 +2616,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT { switch(op_code) { - case PE_UnwindOpCode_PUSH_NONVOL: + case PE_UnwindOpCodeX64_PUSH_NONVOL: { // rjf: read value from stack pointer U64 rsp = regs->rsp.u64; @@ -2638,7 +2638,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT regs->rsp.u64 = new_rsp; }break; - case PE_UnwindOpCode_ALLOC_LARGE: + case PE_UnwindOpCodeX64_ALLOC_LARGE: { // rjf: read alloc size U64 size = 0; @@ -2665,19 +2665,19 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT regs->rsp.u64 = new_rsp; }break; - case PE_UnwindOpCode_ALLOC_SMALL: + case PE_UnwindOpCodeX64_ALLOC_SMALL: { // rjf: advance stack pointer regs->rsp.u64 += op_info*8 + 8; }break; - case PE_UnwindOpCode_SET_FPREG: + case PE_UnwindOpCodeX64_SET_FPREG: { // rjf: put stack pointer back to the frame base regs->rsp.u64 = frame_base; }break; - case PE_UnwindOpCode_SAVE_NONVOL: + case PE_UnwindOpCodeX64_SAVE_NONVOL: { // rjf: read value from frame base U64 off = code_ptr[1].u16*8; @@ -2696,7 +2696,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT reg->u64 = value; }break; - case PE_UnwindOpCode_SAVE_NONVOL_FAR: + case PE_UnwindOpCodeX64_SAVE_NONVOL_FAR: { // rjf: read value from frame base U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); @@ -2715,19 +2715,19 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT reg->u64 = value; }break; - case PE_UnwindOpCode_EPILOG: + case PE_UnwindOpCodeX64_EPILOG: { keep_parsing = 1; }break; - case PE_UnwindOpCode_SPARE_CODE: + case PE_UnwindOpCodeX64_SPARE_CODE: { // TODO(rjf): ??? keep_parsing = 0; is_good = 0; }break; - case PE_UnwindOpCode_SAVE_XMM128: + case PE_UnwindOpCodeX64_SAVE_XMM128: { // rjf: read new register values U8 buf[16]; @@ -2745,7 +2745,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT MemoryCopy(xmm_reg, buf, sizeof(buf)); }break; - case PE_UnwindOpCode_SAVE_XMM128_FAR: + case PE_UnwindOpCodeX64_SAVE_XMM128_FAR: { // rjf: read new register values U8 buf[16]; @@ -2764,7 +2764,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT MemoryCopy(xmm_reg, buf, sizeof(buf)); }break; - case PE_UnwindOpCode_PUSH_MACHFRAME: + case PE_UnwindOpCodeX64_PUSH_MACHFRAME: { // NOTE(rjf): this was found by stepping through kernel code after an exception was // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main @@ -2835,13 +2835,13 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT if(keep_parsing) { U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info.header); - if(!(flags & PE_UnwindInfoFlag_CHAINED)) + if(!(flags & PE_UnwindInfoX64Flag_CHAINED)) { break; } - U64 code_count_rounded = AlignPow2(unwind_info.codes_num, sizeof(PE_UnwindCode)); - U64 code_size = code_count_rounded*sizeof(PE_UnwindCode); - U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; + U64 code_count_rounded = AlignPow2(unwind_info.codes_num, sizeof(PE_UnwindCodeX64)); + U64 code_size = code_count_rounded*sizeof(PE_UnwindCodeX64); + U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfoX64) + code_size; last_pdata = pdata; pdata = push_array(scratch.arena, PE_IntelPdata, 1); if(!ctrl_read_cached_process_memory_struct(process->handle, module->vaddr_range.min+chained_pdata_off, &is_stale, pdata, endt_us) || @@ -2887,6 +2887,1708 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT return result; } +internal PE_Arm64Pdata * +ctrl_arm64_pdata_from_module_voff(Arena *arena, CTRL_Handle module_handle, U64 voff) +{ + PE_Arm64Pdata *first_pdata = 0; + { + U64 hash = ctrl_hash_from_handle(module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->module, module_handle)) + { + PE_Arm64Pdata *pdatas = n->arm64_pdatas; + U64 pdatas_count = n->arm64_pdatas_count; + + if(n->arm64_pdatas_count != 0 && voff >= n->arm64_pdatas[0].voff_first) + { + // NOTE(rjf): + // + // binary search: + // find max index s.t. pdata_array[index].voff_first <= voff + // we assume (i < j) -> (pdata_array[i].voff_first < pdata_array[j].voff_first) + U64 index = pdatas_count; + U64 min = 0; + U64 opl = pdatas_count; + for(;;) + { + U64 mid = (min + opl)/2; + PE_Arm64Pdata *pdata = pdatas + mid; + if(voff < pdata->voff_first) + { + opl = mid; + } + else if(pdata->voff_first < voff) + { + min = mid; + } + else + { + index = mid; + break; + } + if(min + 1 >= opl) + { + index = min; + break; + } + } + + // rjf: if we are in range fill result + { + PE_Arm64Pdata *pdata = pdatas + index; + U32 pdata_flag = pdata->combined & 0x3; + B32 is_good = 1; + U32 function_size = max_U32; + + if (pdata_flag != 0) + { + //- antoniom: packed unwind data + function_size = 4 * ((pdata->combined >> 2) & 0x7ff); + is_good = pdata->voff_first <= voff && voff < (pdata->voff_first + function_size); + } + //- antoniom: xdata will be handled in its own path + + if(is_good) + { + first_pdata = push_array(arena, PE_Arm64Pdata, 1); + MemoryCopyStruct(first_pdata, pdata); + } + } + } + break; + } + } + } + return first_pdata; +} + +typedef struct PE_ParsedPackedUnwindDataArm64 PE_ParsedPackedUnwindDataArm64; +struct PE_ParsedPackedUnwindDataArm64 +{ + U32 function_size; + U32 regf; + U32 regi; + U32 h; + U32 cr; + U32 frame_size; + U32 flags; +}; + +typedef struct PE_ParsedPackedXDataArm64 PE_ParsedPackedXDataArm64; +struct PE_ParsedPackedXDataArm64 +{ + U32 function_size; + U32 exception_data_present; + U32 packed_epilog; + U32 epilog_count; + U32 code_words; +}; + +typedef struct PE_UnwindCodeArm64 PE_UnwindCodeArm64; +struct PE_UnwindCodeArm64 +{ + PE_UnwindOpCodeArm64 op; + U32 reg0; + U32 reg1; + U32 sp_off; + U32 add_to_reg; +}; + + +// TODO(antoniom): use list approach again +internal PE_UnwindCodeArm64 +ctrl_unwind_code_from_packed_unwind_data__pe_arm64(U32 packed_unwind_data, S32 step) +{ + PE_UnwindCodeArm64 result = {0}; + + PE_ParsedPackedUnwindDataArm64 parsed_data = {0}; + parsed_data.function_size = 4 * ((packed_unwind_data >> 2) & 0x7ff); + parsed_data.regf = (packed_unwind_data >> 13) & 0x7; + if(parsed_data.regf != 0) + { + parsed_data.regf += 1; + } + parsed_data.regi = (packed_unwind_data >> 16) & 0xf; + parsed_data.h = (packed_unwind_data >> 20) & 0x1; + parsed_data.cr = (packed_unwind_data >> 21) & 0x3; + parsed_data.frame_size = 16 * ((packed_unwind_data >> 23) & 0x1ff); + + U32 int_size = parsed_data.regi * 8; + U32 float_size = parsed_data.regf * 8; + U32 save_size = ((int_size + float_size + (8 * 8 * parsed_data.h)) + 0xf) & ~0xf; + U32 loc_size = parsed_data.frame_size - save_size; + + if(parsed_data.cr == 1) + { + int_size += 8; + } + + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_end; + } + + if(parsed_data.cr == 2) + { + step -= 1; + if (step == 0) + { + result.op = PE_UnwindOpCodeArm64_pac_sign_lr; + } + } + + if(step > 0) + { + step -= parsed_data.regi & 1; + if (step == 0) + { + if (parsed_data.regi == 1) + { + result.op = PE_UnwindOpCodeArm64_save_regp_x; + result.sp_off = int_size; + } + else + { + result.op = PE_UnwindOpCodeArm64_save_reg; + result.sp_off = int_size - 8; + } + + result.reg0 = parsed_data.regi + OffsetOf(REGS_RegBlockARM64, x0); + if ((parsed_data.regi & 1) && parsed_data.cr == 1) + { + result.op = PE_UnwindOpCodeArm64_save_regp; + result.reg1 = 30 + OffsetOf(REGS_RegBlockARM64, x0); + result.sp_off = int_size - 16; + } + } + } + + if (step > 0) + { + step -= (parsed_data.regi / 2); + if (step <= 0) + { + if (step < 0) + { + result.op = PE_UnwindOpCodeArm64_save_regp; + result.sp_off = 16 * -step; + result.reg0 = 19 + (2 * -step) + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 20 + (2 * -step) + OffsetOf(REGS_RegBlockARM64, x0); + } + else if (step == 0) + { + result.op = PE_UnwindOpCodeArm64_save_regp_x; + result.sp_off = int_size; + result.reg0 = 19 + OffsetOf(REGS_RegBlockARM64, x0);; + result.reg1 = 20 + OffsetOf(REGS_RegBlockARM64, x0);; + } + } + } + + if(step > 0) + { + if(parsed_data.cr == 1 && (parsed_data.regi % 2 == 0)) + { + step -= 1; + if (step == 0) + { + result.op = PE_UnwindOpCodeArm64_save_reg; + result.reg0 = 29 + OffsetOf(REGS_RegBlockARM64, x0);; + result.sp_off = int_size - 8; + } + } + } + + if(step > 0) + { + if(parsed_data.regf & 1) + { + step -= 1; + if(step == 0) + { + if(parsed_data.regf == 1) + { + result.op = PE_UnwindOpCodeArm64_save_freg; + result.sp_off = 8; + result.reg0 = 8 + OffsetOf(REGS_RegBlockARM64, v0); + if(parsed_data.regi == 0 && parsed_data.cr == 0) + { + result.op = PE_UnwindOpCodeArm64_save_freg_x; + } + } + else + { + result.op = PE_UnwindOpCodeArm64_save_freg; + result.sp_off = float_size - 8; + result.reg0 = 8 + parsed_data.regf + OffsetOf(REGS_RegBlockARM64, v0);; + } + } + } + } + + if(step > 0) + { + step -= parsed_data.regf / 2; + if (step == 0) + { + if(parsed_data.regi == 0 && parsed_data.cr == 0) + { + result.op = PE_UnwindOpCodeArm64_save_fregp_x; + } + else + { + result.op = PE_UnwindOpCodeArm64_save_fregp; + } + // TODO(antoniom): check + result.sp_off = int_size + float_size; + result.reg0 = 8 + (2 * -step) + OffsetOf(REGS_RegBlockARM64, v0); + result.reg1 = 9 + (2 * -step) + OffsetOf(REGS_RegBlockARM64, v0); + } + else + { + result.op = PE_UnwindOpCodeArm64_save_fregp; + result.sp_off = int_size + float_size - (16 * -step); + result.reg0 = 8 + OffsetOf(REGS_RegBlockARM64, v0); + result.reg1 = 9 + OffsetOf(REGS_RegBlockARM64, v0); + } + } + + if(step > 0) + { + if(parsed_data.h != 0) + { + step -= 4; + if (step <= 0) + { + result.op = PE_UnwindOpCodeArm64_save_reg; + result.sp_off = int_size + float_size + (16 * -step); + result.reg0 = 2 * -step + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 1 + (2 * -step) + OffsetOf(REGS_RegBlockARM64, x0); + } + } + } + + if((parsed_data.cr == 2 || parsed_data.cr == 3) && parsed_data.frame_size <= 512) + { + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_save_fplr_x; + result.sp_off = loc_size; + result.reg0 = 29 + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 30 + OffsetOf(REGS_RegBlockARM64, x0); + } + } + + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_set_fp; + } + } + } + else if((parsed_data.cr == 2 || parsed_data.cr == 3) && + (512 < parsed_data.frame_size && parsed_data.frame_size <= 4080)) + { + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_alloc_m; + result.sp_off = loc_size; + } + } + + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_save_fplr_x; + result.sp_off = 0; + result.reg0 = 29 + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 30 + OffsetOf(REGS_RegBlockARM64, x0); + } + } + + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_set_fp; + } + } + } + else if((parsed_data.cr == 2 || parsed_data.cr == 3) && + 4080 < parsed_data.frame_size) + { + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_alloc_m; + result.sp_off = 4080; + } + } + + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_alloc_m; + result.sp_off = loc_size - 4080; + } + } + + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_save_fplr_x; + result.sp_off = 0; + result.reg0 = 29 + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 30 + OffsetOf(REGS_RegBlockARM64, x0); + } + } + + if(step > 0) + { + step -= 1; + if(step) + { + result.op = PE_UnwindOpCodeArm64_set_fp; + } + } + } + else if((parsed_data.cr == 0 || parsed_data.cr == 1) && + parsed_data.frame_size <= 4080) + { + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_alloc_m; + result.sp_off = loc_size; + } + } + } + else if((parsed_data.cr == 0 || parsed_data.cr == 1) && + 4080 < parsed_data.frame_size) + { + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_alloc_m; + result.sp_off = 4080; + } + } + + if(step > 0) + { + step -= 1; + if(step == 0) + { + result.op = PE_UnwindOpCodeArm64_alloc_m; + result.sp_off = loc_size - 4080; + } + } + } + + return(result); +} + +internal PE_UnwindCodeArm64 +ctrl_unwind_code_from_xdata__pe_arm64(CTRL_Handle process_handle, U64 endt_us, U64 code_words, U64 xdata_voff, U64 unwind_off_start, S32 step, S32 max_step, B32 *out_is_good, B32 *out_is_stale) +{ + PE_UnwindCodeArm64 result = {0}; + B32 is_good = 1; + B32 is_stale = 0; + U64 unwind_off = unwind_off_start; + B32 keep_parsing = (unwind_off - unwind_off_start) < (code_words * 4); + S32 cur_step = 0; + + if(step < 0) + { + result.op = PE_UnwindOpCodeArm64_end; + keep_parsing = 0; + } + + while(keep_parsing) + { + MemoryZeroStruct(&result); + + U32 unwind_header = 0; + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(xdata_voff+unwind_off, xdata_voff+unwind_off+sizeof(U32)), &is_stale, &unwind_header, endt_us); + is_good = is_good && !is_stale; + + U8 unwind_op = unwind_header & 0xff; + U8 *unwind_header_u8s = (U8*)&unwind_header; + + if((unwind_op >> 5) == 0) + { + // 000xxxxx + // epilog: add sp, sp, (x * 16) + result.op = PE_UnwindOpCodeArm64_alloc_s; + result.sp_off = (unwind_op & 0x1f) * 16; + unwind_off += 1; + } + else if((unwind_op >> 5) == 1) + { + // 001zzzzz + result.op = PE_UnwindOpCodeArm64_save_r19r20_x; + result.sp_off = (unwind_op & 0x1f) * 8; + result.reg0 = 19 + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 20 + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 1; + } + else if((unwind_op >> 6) == 1) + { + // 01zzzzzz + result.op = PE_UnwindOpCodeArm64_save_fplr; + result.sp_off = (unwind_op & 0x3f) * 8; + result.reg0 = 29 + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 30 + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 1; + } + else if((unwind_op >> 6) == 2) + { + // 10zzzzzz + result.op = PE_UnwindOpCodeArm64_save_fplr_x; + result.sp_off = ((unwind_op & 0x3f) + 1) * 8; + result.reg0 = 29 + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 30 + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 1; + } + else if((unwind_op >> 3) == 24) + { + // 11000xxx'xxxxxxxx + U32 stack_size = ((unwind_op & 0x3) << 8) | unwind_header_u8s[1]; + result.op = PE_UnwindOpCodeArm64_alloc_m; + result.sp_off = stack_size * 16; + unwind_off += 2; + } + else if((unwind_op >> 3) == 29) + { + //- antoniom: custom stack cases for asm routines (__security_pop_cookie) + unwind_off += 1; + } + else if((unwind_op >> 2) == 50) + { + // 110010xx'xxzzzzzz + U32 reg_off = ((unwind_op & 0x3) << 2) | ((unwind_header_u8s[1] >> 6) & 0x3); + result.op = PE_UnwindOpCodeArm64_save_regp; + result.sp_off = (unwind_header_u8s[1] & 0x3f) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = reg_off + 1 + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 2; + } + else if((unwind_op >> 2) == 51) + { + // 110011xx'xxzzzzzz + U32 reg_off = ((unwind_op & 0x3) << 2) | ((unwind_header_u8s[1] >> 6) & 0x3); + result.op = PE_UnwindOpCodeArm64_save_regp_x; + result.sp_off = ((unwind_header_u8s[1] & 0x3f) + 1) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = reg_off + 1 + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 2; + } + else if((unwind_op >> 2) == 52) + { + // 110100xx'xxzzzzzz + U32 reg_off = ((unwind_op & 0x3) << 2) | ((unwind_header_u8s[1] >> 6) & 0x3); + result.op = PE_UnwindOpCodeArm64_save_reg; + result.sp_off = (unwind_header_u8s[1] & 0x3f) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 2; + } + else if((unwind_op >> 1) == 106) + { + // 1101010x'xxxzzzzz + U32 reg_off = ((unwind_op & 0x1) << 1) | ((unwind_header_u8s[1] >> 5) & 0x7); + result.op = PE_UnwindOpCodeArm64_save_reg_x; + result.sp_off = ((unwind_header_u8s[1] & 0x1f) + 1) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 2; + } + else if((unwind_op >> 1) == 107) + { + // 1101011x'xxzzzzzz + U32 reg_off = ((unwind_op & 0x1) << 1) | ((unwind_header_u8s[1] >> 6) & 0x3); + result.op = PE_UnwindOpCodeArm64_save_lrpair; + result.sp_off = ((unwind_header_u8s[1] & 0x3f) + 1) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, x0); + result.reg1 = 30 + OffsetOf(REGS_RegBlockARM64, x0); + unwind_off += 2; + } + else if((unwind_op >> 1) == 108) + { + // 1101100x'xxzzzzzz + U32 reg_off = ((unwind_op & 0x1) << 1) | ((unwind_header_u8s[1] >> 6) & 0x3); + result.op = PE_UnwindOpCodeArm64_save_fregp; + result.sp_off = (unwind_header_u8s[1] & 0x3f) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, v0); + result.reg1 = reg_off + 1 + OffsetOf(REGS_RegBlockARM64, v0); + unwind_off += 2; + } + else if((unwind_op >> 1) == 109) + { + // 1101101x'xxzzzzzz + U32 reg_off = ((unwind_op & 0x1) << 1) | ((unwind_header_u8s[1] >> 6) & 0x3); + result.op = PE_UnwindOpCodeArm64_save_fregp_x; + result.sp_off = ((unwind_header_u8s[1] & 0x3f) + 1) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, v0); + result.reg1 = reg_off + 1 + OffsetOf(REGS_RegBlockARM64, v0); + unwind_off += 2; + } + else if((unwind_op >> 1) == 110) + { + // 1101110x'xxzzzzzz + U32 reg_off = ((unwind_op & 0x1) << 1) | ((unwind_header_u8s[1] >> 6) & 0x3); + result.op = PE_UnwindOpCodeArm64_save_freg; + result.sp_off = (unwind_header_u8s[1] & 0x3f) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, v0); + unwind_off += 2; + } + else if(unwind_op == 222) + { + // save_freg_x + // 11011110'xxxzzzzz: + U32 reg_off = (unwind_header_u8s[1] >> 5) & 0x7; + result.op = PE_UnwindOpCodeArm64_save_freg_x; + result.sp_off = ((unwind_header_u8s[1] & 0x1f) + 1) * 8; + result.reg0 = reg_off + OffsetOf(REGS_RegBlockARM64, v0); + unwind_off += 2; + } + else if(unwind_op == 224) + { + // alloc_l + // 11100000'xxxxxxxx'xxxxxxxx'xxxxxxxx + result.op = PE_UnwindOpCodeArm64_alloc_l; + result.sp_off = (unwind_header & 0xffffff) * 16; + unwind_off += 4; + } + else if(unwind_op == 225) + { + // 11100001 + result.op = PE_UnwindOpCodeArm64_set_fp; + unwind_off += 1; + } + else if(unwind_op == 226) + { + // 11100010'xxxxxxxx + result.op = PE_UnwindOpCodeArm64_add_fp; + result.add_to_reg = unwind_header_u8s[1] * 8; + unwind_off += 2; + } + else if(unwind_op == 227) + { + // 11100011 + //- antoniom: skip nops + unwind_off += 1; + } + else if(unwind_op == 228) + { + // 11100100 + result.op = PE_UnwindOpCodeArm64_end; + unwind_off += 1; + keep_parsing = 0; + } + else if(unwind_op == 229) + { + // 11100101 + result.op = PE_UnwindOpCodeArm64_end_c; + unwind_off += 1; + } + else if(unwind_op == 230) + { + // 11100110 + result.op = PE_UnwindOpCodeArm64_save_next; + unwind_off += 1; + } + else if(unwind_op == 231) + { + // 11100111 + unwind_off += 1; + } + else if(unwind_op == 232) + { + // MSFT_OP_TRAP_FRAME + } + else if(unwind_op == 233) + { + // MSFT_OP_MACHINE_FRAME + } + else if(unwind_op == 234) + { + // MSFT_OP_CONTEXT + } + else if(unwind_op == 235) + { + // MSFT_OP_EC_CONTEXT + } + else if(unwind_op == 236) + { + // MSFT_OP_CLEAR_UNWOUND_TO_CALL + } + else if(unwind_op == 252) + { + // 11111100 + // qreg + unwind_off += 1; + } + + if (step == max_step) + { + keep_parsing = 0; + } + step += 1; + keep_parsing = keep_parsing && is_good && ((unwind_off - unwind_off_start) < (code_words * 4)); + } + + *out_is_stale = is_stale; + *out_is_good = is_good && !is_stale; + + return(result); +} + +internal CTRL_UnwindStepResult +ctrl_unwind_step__pe_arm64(CTRL_EntityStore *store, CTRL_Handle process_handle, CTRL_Handle module_handle, REGS_RegBlockARM64 *regs, U64 endt_us) +{ + Temp scratch = scratch_begin(0, 0); + + B32 is_stale = 0; + B32 is_good = 1; + + ////////////////////////////// + //- antoniom: unpack parameters + // + CTRL_Entity *module = ctrl_entity_from_handle(store, module_handle); + CTRL_Entity *process = ctrl_entity_from_handle(store, process_handle); + U64 ip_voff = regs->pc.u64 - module->vaddr_range.min; + + PE_Arm64Pdata *first_pdata = ctrl_arm64_pdata_from_module_voff(scratch.arena, module_handle, ip_voff); + + U64 new_pc = 0; + U64 new_sp = 0; + + U64 function_start_vaddr = first_pdata ? first_pdata->voff_first + module->vaddr_range.min : 0; + U64 function_end_vaddr = 0; + + //- antoniom: find function end vaddr + U32 combined_flag = first_pdata ? first_pdata->combined & 0x3 : 0; + if(first_pdata && combined_flag != 0) + { + U32 packed_unwind_data = first_pdata->combined; + function_end_vaddr = function_start_vaddr + (4 * ((packed_unwind_data >> 2) & 0x7FF)); + } + else if(first_pdata) + { + U64 xdata_voff = first_pdata->combined + module->vaddr_range.min; + U32 header = 0; + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, xdata_voff, &is_stale, &header, endt_us); + is_good = is_good && !is_stale; + function_end_vaddr = function_start_vaddr + (4 * (header & 0x3ffff)); + } + + //- antoniom: check to see if in epilog + B32 has_pdata_and_in_epilog = 0; + if(first_pdata) + { + B32 is_epilog = 0; + B32 keep_parsing = 1; + U64 read_vaddr = regs->pc.u64; + + //- antoniom: only read 16 instructions before the end of the function + Rng1U64 epilog_vaddr_rng = r1u64(function_end_vaddr - 0x40, function_end_vaddr + 0x4); + + //- antoniom: Check to see if in epilog + for(B32 keep_parsing = 1; keep_parsing;) + { + U32 inst = 0; + if(contains_1u64(epilog_vaddr_rng, read_vaddr)) + { + is_good = ctrl_read_cached_process_memory(process_handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, &inst, endt_us); + is_good = is_good && !is_stale; + } + + if(!is_good) + { + keep_parsing = 0; + } + else + { + if((inst & 0xFFC003FF) == 0x910003FF) + { + // add sp, sp, #imm + keep_parsing = 0; + is_epilog = 1; + } + else if((inst & 0xFFC003FF) == 0x8B0003FF) + { + // add sp, sp, reg, lsl #imm + keep_parsing = 0; + is_epilog = 1; + } + else if(inst == 0xD65F03C0) + { + // ret + keep_parsing = 0; + is_epilog = 1; + } + else if((inst & 0xFC000000) == 0x94000000) + { + // bl (e.g. __security_pop_cookie) + // go to next instruction + read_vaddr += 4; + } + else if(inst == 0x910002BF) + { + // mov sp, x29 + keep_parsing = 0; + is_epilog = 1; + } + else if((inst & 0xFFC003E0) == 0xA9C003E0) + { + // ldp reg0, reg1, [sp, #imm] + keep_parsing = 0; + is_epilog = 1; + } + else if((inst & 0xFFC003E0) == 0xA8C003E0) + { + // ldp reg0, reg1, [sp], #imm (post-indexed load) + keep_parsing = 0; + is_epilog = 1; + } + else if((inst & 0xFFE007E0) == 0xF94007E0) + { + // ldr reg0, [sp, #imm] + keep_parsing = 0; + is_epilog = 1; + } + else if((inst & 0xFFE007E0) == 0xF84007E0) + { + // ldr reg0, [sp], #imm (post-indexed_load) + keep_parsing = 0; + is_epilog = 1; + } + else + { + // TODO(antoniom): fregs + keep_parsing = 0; + } + } + } + has_pdata_and_in_epilog = is_epilog; + } + + //- antoniom: pdata & in epilog -> epilog unwind + if(first_pdata && has_pdata_and_in_epilog) + { + U64 read_vaddr = regs->pc.u64; + new_sp = regs->x31.u64; + new_pc = regs->pc.u64; + + for (B32 keep_parsing = 1; keep_parsing;) + { + U32 inst = 0; + is_good = ctrl_read_cached_process_memory(process_handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, &inst, endt_us); + is_good = is_good && !is_stale; + read_vaddr += 4; + + if(is_good) + { + if((inst & 0xFFC003FF) == 0x910003FF) + { + // add sp, sp, #imm + B32 shift = (inst >> 22) & 0x1; + U32 imm = (inst >> 10) & 0xFFF; + new_sp += shift ? (imm << 12) : imm; + } + else if((inst & 0xFFC003FF) == 0x8B0003FF) + { + // add sp, sp, lsl #imm + U8 option = (inst >> 13) & 0x7; + U32 shift_amount = (inst >> 10) & 0x3F; + REGS_Reg64 *reg = ®s->x0 + ((inst >> 16) & 0x1F); + new_sp += (reg->u64 << shift_amount); + } + else if(inst == 0xD65F03C0) + { + // ret + U64 mask = ~0ULL; + mask >>= 17; + new_pc = regs->x30.u64 & mask; + keep_parsing = 0; + } + else if((inst & 0xFC000000) == 0x94000000) + { + // bl (e.g. __security_pop_cookie) + //- antoniom: : it's possible to encounter a security_pop_cookie, which does add sp, sp, #0x10 + S64 sign_extended_imm = ((S64)(inst & 0x3FFFFFF) << 38) >> 38; + U64 branch_read_vaddr = read_vaddr + 4 * sign_extended_imm; + U32 insts[16]; + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(branch_read_vaddr, branch_read_vaddr + sizeof(insts)), &is_stale, insts, endt_us); + is_good = is_good && !is_stale; + if(is_good) for(U32 idx = 0; idx < 16; idx += 1) + { + // add sp, sp, 0x10 -> ret + if(insts[idx] == 0x910043ff && idx < 15 && insts[idx+1] == 0xd65f03c0) + { + new_sp += 0x10; + break; + } + } + keep_parsing = is_good; + } + else if(inst == 0x910002BF) + { + // mov sp, x29 + } + else if((inst & 0xFEC003E0) == 0xA9C003E0) + { + // ldp reg0, reg1, [sp,#imm] + REGS_Reg64 *reg0 = ®s->x0 + (inst & 0x1F); + REGS_Reg64 *reg1 = ®s->x0 + ((inst >> 10) & 0x1F); + + S64 imm = 8 * ((inst >> 15) & 0x7f); + S64 sign_extended_imm = (imm << 58) >> 58; + U64 reg_read_vaddr = (U64)((S64)new_sp + sign_extended_imm); + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®0->u64, endt_us); + is_good = is_good && !is_stale; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr + 8, &is_stale, ®1->u64, endt_us); + is_good = is_good && !is_stale; + keep_parsing = is_good; + } + else if((inst & 0xFEC003E0) == 0xA8C003E0) + { + // ldp reg0, reg1, [sp], #imm (post-indexed load) + REGS_Reg64 *reg0 = ®s->x0 + (inst & 0x1F); + REGS_Reg64 *reg1 = ®s->x0 + ((inst >> 10) & 0x1F); + + S64 imm = 8 * ((inst >> 15) & 0x7f); + S64 sign_extended_imm = (imm << 58) >> 58; + U64 reg_read_vaddr = new_sp; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®0->u64, endt_us); + is_good = is_good && !is_stale; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr + 8, &is_stale, ®1->u64, endt_us); + is_good = is_good && !is_stale; + + new_sp += sign_extended_imm; + keep_parsing = is_good; + } + else if((inst & 0xFFE007E0) == 0xF84007E0) + { + // ldr reg0, [sp,#imm] + REGS_Reg64 *reg = ®s->x0 + (inst & 0x1F); + + // TODO(antoniom): sign-extended? even right? + S64 imm = 8 * ((inst >> 10) & 0xFFF); + U64 reg_read_vaddr = (U64)((S64)new_sp + imm); + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®->u64, endt_us); + is_good = is_good && !is_stale; + keep_parsing = is_good; + } + else if((inst & 0xFFE007E0) == 0xF84007E0) + { + // ldr reg0, [sp], #imm (post-indexed load) + REGS_Reg64 *reg = ®s->x0 + (inst & 0x1F); + + // TODO(antoniom): sign-extended? + S64 imm = 8 * ((inst >> 12) & 0x1FF); + S64 sign_extended_imm = (imm << 54) >> 54; + U64 reg_read_vaddr = new_sp; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®->u64, endt_us); + is_good = is_good && !is_stale; + + new_sp += sign_extended_imm; + keep_parsing = is_good; + } + else if(inst == 0xd50323ff) + { + keep_parsing = 1; + } + else + { + keep_parsing = 0; + } + } + } + } + + B32 has_pdata_and_in_prolog = 0; + if(first_pdata) + { + B32 is_prolog = 0; + U64 read_vaddr = regs->pc.u64; + + for(B32 keep_parsing = 1; keep_parsing;) + { + U32 inst = 0; + + if(contains_1u64(r1u64(function_start_vaddr, function_start_vaddr + 0x30), read_vaddr)) + { + is_good = ctrl_read_cached_process_memory(process_handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, &inst, endt_us); + is_good = is_good && !is_stale; + } + + if(!is_good) + { + keep_parsing = 0; + } + else + { + if((inst & 0xFFC003FF) == 0xD10003FF) + { + // sub sp, sp, #imm + keep_parsing = 0; + is_prolog = 1; + } + else if((inst & 0xFF80001F) == 0xD280000F) + { + // mov x15, #imm + keep_parsing = 0; + is_prolog = 1; + } + else if((inst & 0xFF0003FF) == 0xCB0003FF) + { + // sub sp, sp, reg, lsl #imm + keep_parsing = 0; + is_prolog = 1; + } + else if((inst & 0xFC000000) == 0x94000000) + { + // bl (e.g. __security_pop_cookie) + // go to prev instruction + read_vaddr -= 4; + } + else if(inst == 0x910003fd) + { + // mov x29, sp + keep_parsing = 0; + is_prolog = 1; + } + else if((inst & 0xFFC003E0) == 0xA9000360) + { + // stp reg0, reg1, [sp,#imm] + keep_parsing = 0; + is_prolog = 1; + } + else if((inst & 0xFFC003E0) == 0xA98003E0) + { + // stp reg0, reg1, [sp,#imm]! (pre-indexed load) + keep_parsing = 0; + is_prolog = 1; + } + else if((inst & 0xFFC003E0) == 0xF90003E0) + { + // str reg0, [sp,#imm] + keep_parsing = 0; + U32 str_reg = inst & 0x1f; + if(19 <= str_reg && str_reg <= 30) + { + is_prolog = 1; + } + } + else if((inst & 0xFFE083E0) == 0xF82083E0) + { + // str reg0, [sp,#imm]! (pre-indexed_load) + keep_parsing = 0; + is_prolog = 1; + } + else if(inst == 0xd503237f) + { + // pacibsp + keep_parsing = 0; + is_prolog = 1; + } + else + { + // TODO(antoniom): fregs + keep_parsing = 0; + } + } + } + has_pdata_and_in_prolog = is_prolog; + } + + //- antoniom: pdata & in prolog -> prolog unwind + // need to "undo" previous instructions, so the execution stream + // starts at the previous instruction. This makes operations look + // like the epilog block operations + if (first_pdata && has_pdata_and_in_prolog) + { + U64 read_vaddr = regs->pc.u64 - 4; + new_sp = regs->x31.u64; + new_pc = regs->pc.u64; + + for(B32 keep_parsing = 1; keep_parsing;) + { + U32 inst = 0; + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, read_vaddr, &is_stale, &inst, endt_us); + is_good = is_good && !is_stale; + + if(is_good) + { + if((inst & 0xFFC003FF) == 0xD10003FF) + { + // sub sp, sp, #imm + B32 shift = (inst >> 22) & 0x1; + U32 imm = (inst >> 10) & 0xFFF; + new_sp += shift ? (imm << 12) : imm; + } + else if((inst & 0xFF80001F) == 0xD280000F) + { + // mov x15, #imm + //- antoniom: no need to do anything. + // If this is the first instruction we encouter, + // then it doesn't matter. If the sub sp, sp, x15, lsl #imm + // has been encountered, then the "functional" part of this + // operation has already occurred + } + else if((inst & 0xFF0003FF) == 0xCB0003FF) + { + // sub sp, sp, reg, lsl #imm + U8 option = (inst >> 13) & 0x7; + U32 shift_amount = (inst >> 10) & 0x3F; + REGS_Reg64 *reg = ®s->x0 + ((inst >> 16) & 0x1F); + new_sp += (reg->u64 << shift_amount); + } + else if((inst & 0xFC000000) == 0x94000000) + { + //- antoniom: basically for security_push_cookie. + // Look for sub sp, sp, #0x10. We're undoing it, so we will add 0x10 to sp + S64 sign_extended_imm = ((S64)(inst & 0x3FFFFFF) << 38) >> 38; + U64 branch_read_vaddr = read_vaddr + 4 * sign_extended_imm; + U32 branch_inst = 0; + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, branch_read_vaddr, &is_stale, &branch_inst, endt_us); + is_good = is_good && !is_stale; + if(is_good && branch_inst == 0xd10043ff) + { + new_sp += 0x10; + } + keep_parsing = is_good; + } + else if(inst == 0x910003FD) + { + // mov x29, sp + } + else if((inst & 0xFFC003E0) == 0xA90003E0) + { + // stp reg0, reg1, [sp,#imm] -> do load + REGS_Reg64 *reg0 = ®s->x0 + (inst & 0x1F); + REGS_Reg64 *reg1 = ®s->x0 + ((inst >> 10) & 0x1F); + + //- antoniom: multiply by 8 after? + S64 imm = 8 * ((inst >> 15) & 0x7f); + S64 sign_extended_imm = (imm << 58) >> 58; + U64 reg_read_vaddr = (U64)((S64)new_sp + sign_extended_imm); + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®0->u64, endt_us); + is_good = is_good && !is_stale; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr + 8, &is_stale, ®1->u64, endt_us); + is_good = is_good && !is_stale; + + keep_parsing = is_good; + } + else if((inst & 0xFFC003E0) == 0xA98003E0) + { + // stp reg0, reg1, [sp], #imm (pre-indexed load) -> do post-index load + REGS_Reg64 *reg0 = ®s->x0 + (inst & 0x1F); + REGS_Reg64 *reg1 = ®s->x0 + ((inst >> 10) & 0x1F); + + S64 imm = 8 * ((inst >> 15) & 0x7f); + S64 sign_extended_imm = (imm << 57) >> 57; + sign_extended_imm *= -1; + + U64 reg_read_vaddr = new_sp; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®0->u64, endt_us); + is_good = is_good && !is_stale; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr + 8, &is_stale, ®1->u64, endt_us); + is_good = is_good && !is_stale; + + new_sp += sign_extended_imm; + keep_parsing = is_good; + } + else if((inst & 0xFFC003E0) == 0xF90003E0) + { + // str reg0, [sp,#imm] -> do load + REGS_Reg64 *reg = ®s->x0 + (inst & 0x1F); + + S64 unsigned_imm = 8 * ((inst >> 10) & 0xFFF); + U64 reg_read_vaddr = (U64)((S64)new_sp + unsigned_imm); + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®->u64, endt_us); + is_good = is_good && !is_stale; + + keep_parsing = is_good; + } + else if((inst & 0xFFE083E0) == 0xF82083E0) + { + // str reg0, [sp], #imm (post-indexed load) -> do pre-indexed ldr + REGS_Reg64 *reg = ®s->x0 + (inst & 0x1F); + + S64 imm = ((inst >> 10) & 0x1FF); + S64 sign_extended_imm = (imm << 54) >> 54; + U64 reg_read_vaddr = new_sp; + + is_good = is_good && ctrl_read_cached_process_memory_struct(process_handle, reg_read_vaddr, &is_stale, ®->u64, endt_us); + is_good = is_good && !is_stale; + + new_sp += sign_extended_imm; + + keep_parsing = is_good; + } + else + { + // TODO(antoniom): fregs + keep_parsing = 0; + } + } + keep_parsing = keep_parsing && (read_vaddr >= function_start_vaddr); + read_vaddr -= 4; + } + + //- antoniom: simulate ret + U64 mask = ~0ULL; + mask >>= 17; + new_pc = regs->x30.u64 & mask; + } + + ////////////////////////////// + //- antoniom: pdata & not in epilog/prolog -> xdata unwind + // + if(is_good && first_pdata && !has_pdata_and_in_epilog && !has_pdata_and_in_prolog) + { + B32 is_packed_unwind_data = 0; + B32 is_xdata = 0; + + PE_Arm64Pdata *pdata = first_pdata; + + U64 xdata_code_words = 0; + U64 xdata_code_words_ptr = 0; + U64 xdata_step_count = 0; + U64 xdata_voff = 0; + U64 xdata_off = 0; + + U64 packed_unwind_count = 0; + + if(is_good && combined_flag != 0) + { + is_packed_unwind_data = 1; + + if (is_good) + { + U32 packed_unwind_data = pdata->combined; + PE_ParsedPackedUnwindDataArm64 parsed_data = {0}; + parsed_data.function_size = 4 * ((packed_unwind_data >> 2) & 0x7FF); + parsed_data.regf = (packed_unwind_data >> 13) & 0x7; + if(parsed_data.regf != 0) + { + parsed_data.regf += 1; + } + parsed_data.regi = (packed_unwind_data >> 16) & 0xf; + parsed_data.h = (packed_unwind_data >> 20) & 0x1; + parsed_data.cr = (packed_unwind_data >> 21) & 0x3; + parsed_data.frame_size = 16 * ((packed_unwind_data >> 23) & 0x1FF); + + if(parsed_data.cr == 2) + { + packed_unwind_count += 1; + } + + U32 regi_count = (parsed_data.regi / 2) + (parsed_data.regi & 0x1); + packed_unwind_count += regi_count; + if(parsed_data.cr == 1 && (parsed_data.regi % 2 == 0)) + { + packed_unwind_count += 1; + } + + // TODO(antoniom): review + U32 regf_count = (parsed_data.regf / 2) + (parsed_data.regf & 0x1); + packed_unwind_count += regf_count; + + if(parsed_data.h != 0) + { + packed_unwind_count += 4; + } + + if((parsed_data.cr == 2 || parsed_data.cr == 3) && parsed_data.frame_size <= 512) + { + packed_unwind_count += 2; + } + else if((parsed_data.cr == 2 || parsed_data.cr == 3) && + (512 < parsed_data.frame_size && parsed_data.frame_size <= 4080)) + { + packed_unwind_count += 3; + } + else if((parsed_data.cr == 2 || parsed_data.cr == 3) && + 4080 < parsed_data.frame_size) + { + packed_unwind_count += 4; + } + else if((parsed_data.cr == 0 || parsed_data.cr == 1) && + parsed_data.frame_size <= 4080) + { + packed_unwind_count += 1; + } + else if((parsed_data.cr == 0 || parsed_data.cr == 1) && + 4080 < parsed_data.frame_size) + { + packed_unwind_count += 2; + } + } + } + else if (is_good) + { + is_xdata = 1; + + xdata_voff = pdata->combined + module->vaddr_range.min; + xdata_off = 0; + + PE_ParsedPackedXDataArm64 parsed_data = {0}; + if(is_good) + { + U32 header = 0; + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(xdata_voff+xdata_off, xdata_voff+xdata_off+sizeof(U32)), &is_stale, &header, endt_us); + is_good = is_good && !is_stale; + + parsed_data.function_size = 4 * (header & 0x3ffff); + parsed_data.exception_data_present = (header >> 20) & 0x1; + parsed_data.packed_epilog = (header >> 21) & 0x1; + parsed_data.epilog_count = (header >> 22) & 0x1f; + parsed_data.code_words = (header >> 27) & 0x1f; + } + + is_good = is_good && (pdata->voff_first <= ip_voff && ip_voff < (pdata->voff_first + parsed_data.function_size)); + + if(is_good && parsed_data.code_words == 0 && parsed_data.epilog_count == 0) + { + xdata_off += 4; + + U32 ext_header = 0; + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(xdata_voff+xdata_off, xdata_voff+xdata_off+sizeof(U32)), &is_stale, &ext_header, endt_us); + is_good = is_good && !is_stale; + + if(is_good) + { + parsed_data.epilog_count = ext_header & 0xffff; + parsed_data.code_words = (ext_header >> 16) & 0xff; + } + } + + xdata_off += 4; + + if(parsed_data.packed_epilog == 0) + { + //- antoniom: epilog scope + U64 epilog_scope_ptr = xdata_voff + xdata_off; + U32 min_epilog_offset = max_U32; + U32 min_unwind_code_offset = max_U32; + for(U32 epilog_scope_idx = 0; is_good && !is_stale && epilog_scope_idx < parsed_data.epilog_count; epilog_scope_idx += 1) + { + U32 epilog_scope_header = 0; + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(epilog_scope_ptr, epilog_scope_ptr+sizeof(U32)), &is_stale, &epilog_scope_header, endt_us); + is_good = is_good && !is_stale; + + U32 epilog_offset = 4 * (epilog_scope_header & 0x3ffff); + if(epilog_offset < min_epilog_offset) + { + min_epilog_offset = epilog_offset; + } + + U32 unwind_code_offset = (epilog_scope_header >> 22) & 0x3ff; + if(unwind_code_offset < min_unwind_code_offset) + { + min_unwind_code_offset = unwind_code_offset; + } + } + + if(min_epilog_offset < max_U32) + { + xdata_off += parsed_data.epilog_count * 4 + min_unwind_code_offset; + } + } + + xdata_code_words_ptr = xdata_voff + xdata_off; + xdata_code_words = parsed_data.code_words; + + U64 unwind_off = xdata_off; + B32 keep_parsing = (unwind_off - xdata_off) <= (4 * parsed_data.code_words); + while(keep_parsing) + { + U32 unwind_header = 0; + + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(xdata_voff+unwind_off, xdata_voff+unwind_off+sizeof(U32)), &is_stale, &unwind_header, endt_us); + is_good = is_good && !is_stale; + + U8 unwind_op = unwind_header & 0xff; + U8 *unwind_header_u8s = (U8*)&unwind_header; + + if((unwind_op >> 5) == 0) + { + // 000xxxxx + // epilog: add sp, sp, (x * 16) + unwind_off += 1; + } + else if((unwind_op >> 5) == 1) + { + // 001zzzzz + unwind_off += 1; + } + else if((unwind_op >> 6) == 1) + { + // 01zzzzzz + unwind_off += 1; + } + else if((unwind_op >> 6) == 2) + { + // 10zzzzzz + unwind_off += 1; + } + else if((unwind_op >> 3) == 24) + { + // 11000xxx'xxxxxxxx + unwind_off += 2; + } + else if((unwind_op >> 3) == 29) + { + // custom stack cases for asm routines + unwind_off += 1; + } + else if((unwind_op >> 2) == 50) + { + // 110010xx'xxzzzzzz + unwind_off += 2; + } + else if((unwind_op >> 2) == 51) + { + // 110011xx'xxzzzzzz + unwind_off += 2; + } + else if((unwind_op >> 2) == 52) + { + // 110100xx'xxzzzzzz + unwind_off += 2; + } + else if((unwind_op >> 1) == 106) + { + // 1101010x'xxxzzzzz + unwind_off += 2; + } + else if((unwind_op >> 1) == 107) + { + // 1101011x'xxzzzzzz + unwind_off += 2; + } + else if((unwind_op >> 1) == 108) + { + // 1101100x'xxzzzzzz + unwind_off += 2; + } + else if((unwind_op >> 1) == 109) + { + // 1101101x'xxzzzzzz + unwind_off += 2; + } + else if((unwind_op >> 1) == 110) + { + // 1101110x'xxzzzzzz + unwind_off += 2; + } + else if(unwind_op == 222) + { + // save_freg_x + // 11011110'xxxzzzzz: + unwind_off += 2; + } + else if(unwind_op == 224) + { + // alloc_l + // 11100000'xxxxxxxx'xxxxxxxx'xxxxxxxx + unwind_off += 4; + } + else if(unwind_op == 225) + { + // 11100001 + unwind_off += 1; + } + else if(unwind_op == 226) + { + // 11100010'xxxxxxxx + unwind_off += 2; + } + else if(unwind_op == 227) + { + // 11100011 + //- antoniom: skip nops + unwind_off += 1; + } + else if(unwind_op == 228) + { + // 11100100 + unwind_off += 1; + keep_parsing = 0; + } + else if(unwind_op == 229) + { + // 11100101 + unwind_off += 1; + } + else if(unwind_op == 230) + { + // 11100110 + unwind_off += 1; + } + else if(unwind_op == 231) + { + // 11100111 + unwind_off += 1; + } + else if(unwind_op == 232) + { + // MSFT_OP_TRAP_FRAME + } + else if(unwind_op == 233) + { + // MSFT_OP_MACHINE_FRAME + } + else if(unwind_op == 234) + { + // MSFT_OP_CONTEXT + } + else if(unwind_op == 235) + { + // MSFT_OP_EC_CONTEXT + } + else if(unwind_op == 236) + { + // MSFT_OP_CLEAR_UNWOUND_TO_CALL + } + else if(unwind_op == 252) + { + // 11111100 + // qreg + unwind_off += 1; + } + + xdata_step_count += 1; + keep_parsing = keep_parsing && ((unwind_off - xdata_off) < (parsed_data.code_words * 4)); + } + } + + is_good = is_good && !is_stale; + if (is_good) + { + U32 step = 0; + + if(is_packed_unwind_data) + { + step = packed_unwind_count; + } + else if(is_xdata) + { + step = xdata_step_count; + } + + new_sp = regs->x31.u64; + + if(is_good) for(B32 keep_processing = 1; keep_processing;) + { + PE_UnwindCodeArm64 unwind_code; + + if(is_good && is_packed_unwind_data) + { + unwind_code = ctrl_unwind_code_from_packed_unwind_data__pe_arm64(pdata->combined, step); + } + else if(is_good && is_xdata) + { + unwind_code = ctrl_unwind_code_from_xdata__pe_arm64(process_handle, endt_us, xdata_code_words, xdata_voff, xdata_off, step, xdata_step_count, &is_good, &is_stale); + } + + keep_processing = is_good; + switch(unwind_code.op) + { + default:{}break; + + case PE_UnwindOpCodeArm64_nop: {}break; + + case PE_UnwindOpCodeArm64_MSFT_OP_TRAP_FRAME: + case PE_UnwindOpCodeArm64_MSFT_OP_MACHINE_FRAME: + case PE_UnwindOpCodeArm64_MSFT_OP_CONTEXT: + case PE_UnwindOpCodeArm64_MSFT_OP_EC_CONTEXT: + case PE_UnwindOpCodeArm64_MSFT_OP_CLEAR_UNWOUND_TO_CALL: + { + }break; + + case PE_UnwindOpCodeArm64_end_c: + { + Assert(!"Wait until this is encountered"); + }break; + + case PE_UnwindOpCodeArm64_alloc_s: + case PE_UnwindOpCodeArm64_alloc_m: + case PE_UnwindOpCodeArm64_alloc_l: + { + new_sp += unwind_code.sp_off; + }break; + + case PE_UnwindOpCodeArm64_pac_sign_lr: + { + //- antoniom: treating as no-op, aren't allowed to read "secret" registers + // used for generating the hash + }break; + + case PE_UnwindOpCodeArm64_save_r19r20_x: + case PE_UnwindOpCodeArm64_save_fplr: + case PE_UnwindOpCodeArm64_save_fplr_x: + case PE_UnwindOpCodeArm64_save_regp: + case PE_UnwindOpCodeArm64_save_regp_x: + case PE_UnwindOpCodeArm64_save_reg: + case PE_UnwindOpCodeArm64_save_reg_x: + case PE_UnwindOpCodeArm64_save_lrpair: + case PE_UnwindOpCodeArm64_save_fregp: + case PE_UnwindOpCodeArm64_save_fregp_x: + case PE_UnwindOpCodeArm64_save_freg: + case PE_UnwindOpCodeArm64_save_freg_x: + case PE_UnwindOpCodeArm64_save_qregp: + case PE_UnwindOpCodeArm64_save_qregp_x: + { + // 0 is not a valid value for unwind.reg0/reg1 + REGS_Reg64 *first_reg = ®s->x0 + unwind_code.reg0; + REGS_Reg64 *second_reg = (unwind_code.reg1) ? ®s->x0 + unwind_code.reg1 : 0; + + U64 first_reg_mask = ~0ULL; + U64 second_reg_mask = ~0ULL; + + U64 sp = new_sp; + U64 sp_off = unwind_code.sp_off; + + if(unwind_code.op == PE_UnwindOpCodeArm64_save_fplr || unwind_code.op == PE_UnwindOpCodeArm64_save_fplr_x) + { + //- antoniom: assume a user-mode module + second_reg_mask >>= 17; + } + + if(PE_UnwindOpCodeArm64_save_r19r20_x <= unwind_code.op && unwind_code.op <= PE_UnwindOpCodeArm64_save_freg_x) + { + sp_off = 0; + } + + if(first_reg) + { + U64 first_reg_read = 0; + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(sp+sp_off, sp+sp_off+sizeof(first_reg_read)), &is_stale, &first_reg_read, endt_us); + is_good = is_good && !is_stale; + if(is_good) + { + first_reg->u64 = first_reg_read & first_reg_mask; + } + else + { + is_good = 0; + } + } + + if(second_reg) + { + U64 second_reg_read = 0; + is_good = is_good && ctrl_read_cached_process_memory(process_handle, r1u64(sp+sp_off+8, sp+sp_off+8+sizeof(second_reg_read)), &is_stale, &second_reg_read, endt_us); + is_good = is_good && !is_stale; + if(is_good) + { + second_reg->u64 = second_reg_read & second_reg_mask; + } + else + { + is_good = 0; + } + } + + if(PE_UnwindOpCodeArm64_save_r19r20_x <= unwind_code.op && unwind_code.op <= PE_UnwindOpCodeArm64_save_freg_x) + { + new_sp += unwind_code.sp_off; + } + }break; + + case PE_UnwindOpCodeArm64_set_fp: + { + regs->x31.u64 = regs->x29.u64; + new_sp = regs->x29.u64; + }break; + case PE_UnwindOpCodeArm64_add_fp: + { + Assert(!"Hit this"); + regs->x29.u64 = regs->x31.u64 + unwind_code.add_to_reg; + }break; + case PE_UnwindOpCodeArm64_end: + { + keep_processing = 0; + U64 mask = ~0ULL; + mask >>= 17; + new_pc = regs->x30.u64 & mask; + }break; + // TODO(antoniom): entry_thunks contain q* saves + case PE_UnwindOpCodeArm64_save_next: + { + // TODO(antoniom): need to keep track of Int/FP pair + // TODO(antoniom): keep track and need to see ahead/behind depending on direction + }break; + } + + step -= 1; + } + } + } + + if(is_good && !first_pdata) + { + U64 mask = ~0ULL; + mask >>= 17; + new_pc = regs->x30.u64 & mask; + new_sp = regs->x31.u64; + } + + CTRL_UnwindStepResult result = {0}; + + if(!is_good) {result.flags |= CTRL_UnwindFlag_Error;} + if(is_stale) {result.flags |= CTRL_UnwindFlag_Stale;} + + if(is_good && !is_stale) + { + regs->pc.u64 = new_pc; + regs->x31.u64 = new_sp; + } + + scratch_end(scratch); + return result; +} + //- rjf: abstracted unwind step internal CTRL_UnwindStepResult @@ -2900,6 +4602,10 @@ ctrl_unwind_step(CTRL_EntityStore *store, CTRL_Handle process, CTRL_Handle modul { result = ctrl_unwind_step__pe_x64(store, process, module, (REGS_RegBlockX64 *)reg_block, endt_us); }break; + case Arch_arm64: + { + result = ctrl_unwind_step__pe_arm64(store, process, module, (REGS_RegBlockARM64 *)reg_block, endt_us); + }break; } return result; } @@ -3447,12 +5153,16 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_Handle pro internal void ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_range, String8 path) { + Temp scratch = scratch_begin(0, 0); + ////////////////////////////// //- rjf: parse module image info // Arena *arena = arena_alloc(); - PE_IntelPdata *pdatas = 0; - U64 pdatas_count = 0; + PE_IntelPdata *intel_pdatas = 0; + U64 intel_pdatas_count = 0; + PE_Arm64Pdata *arm64_pdatas = 0; + U64 arm64_pdatas_count = 0; U64 entry_point_voff = 0; Rng1U64 tls_vaddr_range = {0}; U32 pdb_dbg_time = 0; @@ -3546,20 +5256,109 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ reported_data_dir_count = pe_optional.data_dir_count; }break; } - + + //- antoniom: find section count and section array offset + U32 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); + U64 after_coff_header_off = coff_header_off + sizeof(coff_header); + U64 after_optional_header_off = after_coff_header_off + opt_ext_size; + + Rng1U64 optional_range = {0}; + optional_range.min = ClampTop(after_coff_header_off, dim_1u64(vaddr_range)); + optional_range.max = ClampTop(after_optional_header_off, dim_1u64(vaddr_range)); + + U64 section_array_offset = optional_range.max; + COFF_SectionHeader *sec_array = (COFF_SectionHeader*)(vaddr_range.min + section_array_offset); + U64 sec_array_raw_opl = section_array_offset + coff_header.section_count*sizeof(COFF_SectionHeader); + U64 sec_array_opl = ClampTop(sec_array_raw_opl, dim_1u64(vaddr_range)); + U64 section_count = (sec_array_opl - section_array_offset)/sizeof(COFF_SectionHeader); + + COFF_SectionHeader *loaded_sec_array = push_array(scratch.arena, COFF_SectionHeader, section_count); + dmn_process_read(process.dmn_handle, rng_1u64(vaddr_range.min+section_array_offset,vaddr_range.min+section_array_offset+sizeof(COFF_SectionHeader)*section_count), loaded_sec_array); + // rjf: find number of data directories U32 data_dir_max = (opt_ext_size - reported_data_dir_offset) / sizeof(PE_DataDirectory); data_dir_count = ClampTop(reported_data_dir_count, data_dir_max); + // antoniom: detect if ARM64EC binary + COFF_MachineType machine_type = coff_header.machine; + PE_LoadConfig64 load_config_header = {0}; + + U64 pdata_voff = 0; + U64 pdata_size = 0; + B32 is_arm64ec = 0; + + if (PE_DataDirectoryIndex_LOAD_CONFIG < data_dir_count) + { + U64 dir_offset = vaddr_range.min + optional_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_LOAD_CONFIG; + PE_DataDirectory data_dir = {0}; + dmn_process_read_struct(process.dmn_handle, dir_offset, &data_dir); + + switch(optional_magic) + { + case PE_PE32PLUS_MAGIC: + { + dmn_process_read_struct(process.dmn_handle, vaddr_range.min + data_dir.virt_off, &load_config_header); + }break; + case PE_PE32_MAGIC: + { + PE_LoadConfig32 load_config_header32 = {0}; + dmn_process_read_struct(process.dmn_handle, vaddr_range.min + data_dir.virt_off, &load_config_header32); + load_config_header.size = load_config_header32.size; + load_config_header.chpe_metadata_ptr = load_config_header32.chpe_metadata_ptr; + }break; + } + } + + if (load_config_header.size >= OffsetOf(PE_LoadConfig64, chpe_metadata_ptr) && load_config_header.chpe_metadata_ptr != 0) + { + machine_type = COFF_MachineType_ARM64; + + PE_ARM64ECMetadata arm64ec_metadata = {0}; + dmn_process_read_struct(process.dmn_handle, load_config_header.chpe_metadata_ptr, &arm64ec_metadata); + + for(U32 section_idx = 0; section_idx < section_count; section_idx += 1) + { + COFF_SectionHeader *cur_sec = loaded_sec_array + section_idx; + String8 cur_sec_name = str8_cstring_capped(cur_sec->name, cur_sec->name + sizeof(cur_sec->name)); + if(str8_match(cur_sec_name, str8_lit(".pdata"), 0)) + { + pdata_voff = cur_sec->voff; + pdata_size = cur_sec->vsize; + is_arm64ec = 1; + break; + } + } + // TODO(antonio): get hybrid code ranges for arm64ec + } + // rjf: grab pdatas from exceptions section if(data_dir_count > PE_DataDirectoryIndex_EXCEPTIONS) { PE_DataDirectory dir = {0}; dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXCEPTIONS, &dir); Rng1U64 pdatas_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); - pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); - pdatas = push_array(arena, PE_IntelPdata, pdatas_count); - dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), pdatas); + if(is_arm64ec) + { + pdatas_voff_range = r1u64(pdata_voff, pdata_voff + pdata_size); + } + + switch(machine_type) + { + case COFF_MachineType_X86: + case COFF_MachineType_X64: + { + intel_pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); + intel_pdatas = push_array(arena, PE_IntelPdata, intel_pdatas_count); + dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), intel_pdatas); + }break; + + case COFF_MachineType_ARM64: + { + arm64_pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_Arm64Pdata); + arm64_pdatas = push_array(arena, PE_Arm64Pdata, arm64_pdatas_count); + dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), arm64_pdatas); + }break; + } } // rjf: extract tls header @@ -3569,7 +5368,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ PE_DataDirectory dir = {0}; dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, &dir); Rng1U64 tls_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); - switch(coff_header.machine) + switch(machine_type) { default:{}break; case COFF_MachineType_X86: @@ -3583,6 +5382,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; tls_header.characteristics = (U64)tls_header32.characteristics; }break; + case COFF_MachineType_ARM64: case COFF_MachineType_X64: { dmn_process_read_struct(process.dmn_handle, vaddr_range.min + tls_voff_range.min, &tls_header); @@ -3729,13 +5529,16 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ DLLPushBack(slot->first, slot->last, node); node->module = module; node->arena = arena; - node->pdatas = pdatas; - node->pdatas_count = pdatas_count; + node->intel_pdatas = intel_pdatas; + node->intel_pdatas_count = intel_pdatas_count; + node->arm64_pdatas = arm64_pdatas; + node->arm64_pdatas_count = arm64_pdatas_count; node->entry_point_voff = entry_point_voff; node->initial_debug_info_path = initial_debug_info_path; } } } + scratch_end(scratch); } internal void @@ -3943,14 +5746,32 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, { CTRL_Entity *spoof_process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, spoof->process)); Arch arch = spoof_process->arch; - size_of_spoof = bit_size_from_arch(arch)/8; - dmn_process_read(spoof_process->handle.dmn_handle, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); + switch(arch) + { + default: {}break; + case Arch_x64: + case Arch_x86: + { + size_of_spoof = bit_size_from_arch(arch)/8; + dmn_process_read(spoof_process->handle.dmn_handle, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); + }break; + } } // rjf: set spoof if(do_spoof) ProfScope("set spoof") { - dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof->new_ip_value); + CTRL_Entity *spoof_process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, spoof->process)); + Arch arch = spoof_process->arch; + switch(arch) + { + default: {}break; + case Arch_x64: + case Arch_x86: + { + dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof->new_ip_value); + }break; + } } // rjf: run for new events @@ -3997,7 +5818,16 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, // rjf: unset spoof if(do_spoof) ProfScope("unset spoof") { - dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); + CTRL_Entity *spoof_process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, spoof->process)); + Arch arch = spoof_process->arch; + switch(arch) + { + default: {}break; + case Arch_x64: + { + dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); + }break; + } } } } @@ -4764,7 +6594,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) CTRL_Handle target_thread = msg->entity; CTRL_Handle target_process = msg->parent; CTRL_Entity *target_process_entity = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, target_process); - U64 spoof_ip_vaddr = 911; + //- antoniom: ARM64 requires that instructions be 32-bit aligned + U64 spoof_ip_vaddr = 912; log_infof("ctrl_thread__run:\n{\n"); ////////////////////////////// @@ -5705,12 +7536,22 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { // rjf: setup spoof mode begin_spoof_mode = 1; - U64 spoof_sp = dmn_rsp_from_thread(target_thread.dmn_handle); spoof_mode = 1; spoof.process = target_process.dmn_handle; spoof.thread = target_thread.dmn_handle; - spoof.vaddr = spoof_sp; spoof.new_ip_value = spoof_ip_vaddr; + + switch(arch) + { + default: {}break; + case Arch_x64: + case Arch_x86: + { + U64 spoof_sp = dmn_rsp_from_thread(target_thread.dmn_handle); + spoof.vaddr = spoof_sp; + }break; + } + log_infof("spoof:{process:[0x%I64x], thread:[0x%I64x], vaddr:0x%I64x, new_ip_value:0x%I64x}\n", spoof.process.u64[0], spoof.thread.u64[0], spoof.vaddr, spoof.new_ip_value); } } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 3540e87ff..5abfb6e1c 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -808,13 +808,15 @@ struct CTRL_ModuleImageInfoCacheNode { CTRL_ModuleImageInfoCacheNode *next; CTRL_ModuleImageInfoCacheNode *prev; - CTRL_Handle module; - Arena *arena; - PE_IntelPdata *pdatas; - U64 pdatas_count; - U64 entry_point_voff; - Rng1U64 tls_vaddr_range; - String8 initial_debug_info_path; + CTRL_Handle module; + Arena *arena; + PE_IntelPdata *intel_pdatas; + U64 intel_pdatas_count; + PE_Arm64Pdata *arm64_pdatas; + U64 arm64_pdatas_count; + U64 entry_point_voff; + Rng1U64 tls_vaddr_range; + String8 initial_debug_info_path; }; typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; @@ -1096,6 +1098,7 @@ internal B32 ctrl_thread_write_reg_block(CTRL_Handle thread, void *block); //- rjf: cache lookups internal PE_IntelPdata *ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_Handle module_handle, U64 voff); +internal PE_Arm64Pdata *ctrl_arm64_pdata_from_module_voff(Arena *arena, CTRL_Handle module_handle, U64 voff); internal U64 ctrl_entry_point_voff_from_module(CTRL_Handle module_handle); internal Rng1U64 ctrl_tls_vaddr_range_from_module(CTRL_Handle module_handle); internal String8 ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_Handle module_handle); @@ -1110,6 +1113,9 @@ internal CTRL_Unwind ctrl_unwind_deep_copy(Arena *arena, Arch arch, CTRL_Unwind internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CTRL_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us); +//- antoniom: [arm64] +internal CTRL_UnwindStepResult ctrl_unwind_step__pe_arm64(CTRL_EntityStore *store, CTRL_Handle process_handle, CTRL_Handle module_handle, REGS_RegBlockARM64 *regs, U64 endt_us); + //- rjf: abstracted unwind step internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_EntityStore *store, CTRL_Handle process, CTRL_Handle module, Arch arch, void *reg_block, U64 endt_us); diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index a8aa67769..8a5601495 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -9,6 +9,22 @@ #include "third_party/zydis/zydis.c" #endif +#include "third_party/armadillo/source/armadillo.h" +#include "third_party/armadillo/source/bits.h" +#include "third_party/armadillo/source/utils.h" +#include "third_party/armadillo/source/strext.h" + +#include "third_party/armadillo/source/utils.c" +#include "third_party/armadillo/source/bits.c" +#include "third_party/armadillo/source/strext.c" +#include "third_party/armadillo/source/BranchExcSys.c" +#include "third_party/armadillo/source/DataProcessingFloatingPoint.c" +#include "third_party/armadillo/source/DataProcessingImmediate.c" +#include "third_party/armadillo/source/DataProcessingRegister.c" +#include "third_party/armadillo/source/LoadsAndStores.c" +#include "third_party/armadillo/source/instruction.c" +#include "third_party/armadillo/source/armadillo.c" + internal DASM_Inst dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Syntax syntax) { @@ -16,6 +32,181 @@ dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Synta switch(arch) { default:{}break; + + //- antoniom: arm64 disassembly + case Arch_arm64: + { + DASM_InstFlags flags = 0; + S64 rel_voff = 0; + S64 sp_delta = 0; + + U32 opcode = *((U32*)code.str); + struct ad_insn *insn = 0; + ArmadilloDisassemble(opcode, vaddr, &insn); + { + S32 code = insn->instr_id; + + switch(code) + { + // antoniom: changes x30 + case AD_INSTR_BL: + { + flags |= DASM_InstFlag_Call; + rel_voff = insn->operands->op_imm.bits; + }break; + + // antoniom: changes x30 + // offset comes from register + case AD_INSTR_BLR: + case AD_INSTR_BLRAAZ: + case AD_INSTR_BLRAA: + case AD_INSTR_BLRABZ: + case AD_INSTR_BLRAB: + { + flags |= DASM_InstFlag_Call; + }break; + + case AD_INSTR_B: + { + rel_voff = insn->operands->op_imm.bits; + + if (insn->cc == -1) + { + flags |= DASM_InstFlag_UnconditionalJump; + } + else + { + flags |= DASM_InstFlag_Branch; + } + }break; + + // antoniom: does not change x30 + case AD_INSTR_BR: + { + flags |= DASM_InstFlag_UnconditionalJump; + }break; + + case AD_INSTR_CBZ: + case AD_INSTR_CBNZ: + { + flags |= DASM_InstFlag_Branch; + struct ad_operand *imm_op = insn->operands; + rel_voff = imm_op->op_imm.bits & (~(-1LL << 19)); + }break; + + case AD_INSTR_TBZ: + case AD_INSTR_TBNZ: + { + flags |= DASM_InstFlag_Branch; + struct ad_operand *imm_op = insn->operands; + rel_voff = imm_op->op_imm.bits & (~(-1LL << 14)); + }break; + + case AD_INSTR_BRAA: + case AD_INSTR_BRAAZ: + case AD_INSTR_BRAB: + case AD_INSTR_BRABZ: + { + flags |= DASM_InstFlag_Branch; + }break; + + case AD_INSTR_ERET: + case AD_INSTR_ERETAA: + case AD_INSTR_ERETAB: + case AD_INSTR_RET: + case AD_INSTR_RETAA: + case AD_INSTR_RETAB: + { + flags |= DASM_InstFlag_Return; + }break; + + default: + { + flags |= DASM_InstFlag_NonFlow; + }break; + } + + //- antoniom: check for stack pointer modifications + if(insn->num_operands > 0) + { + struct ad_operand *dst_op = insn->operands; + if(dst_op && dst_op->type == AD_OP_REG && + (dst_op->op_reg.rn == AD_REG_SP || dst_op->op_reg.rn == 31) && dst_op->op_reg.zr == 0) + { + flags |= DASM_InstFlag_ChangesStackPointer; + + struct ad_operand *src_op_0 = insn->operands + 1; + struct ad_operand *src_op_1 = insn->operands + 2; + + B32 first_src_sp = (src_op_0 && src_op_0->type == AD_OP_REG && + (src_op_0->op_reg.rn == AD_REG_SP || src_op_0->op_reg.rn == 31) && + src_op_0->op_reg.zr == 0); + B32 second_src_imm = (src_op_1 && src_op_1->type == AD_OP_IMM); + + if(code == AD_INSTR_SUB && first_src_sp && second_src_imm) + { + sp_delta = -1 * src_op_1->op_imm.bits; + } + else if(code == AD_INSTR_ADD && first_src_sp && second_src_imm) + { + S64 sign = src_op_1->op_imm.bits; + } + else + { + flags |= DASM_InstFlag_ChangesStackPointerVariably; + } + } + + //- antoniom: this is a simple check for stp, str, ldp, ldr, etc. + // e.g. + // stp x29, x30, [sp, #-0x20]! + if (insn->num_operands > 2) + { + struct ad_operand *index_dst = 0; + struct ad_operand *index_imm = 0; + + // 1 -> post + // 3 -> pre + if (insn->post_pre_index == 1 || insn->post_pre_index == 3) + { + index_dst = insn->operands + insn->num_operands - 2; + index_imm = insn->operands + insn->num_operands - 1; + flags |= DASM_InstFlag_ChangesStackPointer; + } + + if (index_dst && index_imm && index_dst->type == AD_OP_REG && index_dst->op_reg.rn == 31) + { + if (index_imm->type == AD_OP_IMM) switch(index_imm->op_imm.type) + { + default: {}break; + case AD_IMM_INT: + case AD_IMM_LONG: + { + sp_delta += (S64)index_imm->op_imm.bits; + }break; + case AD_IMM_UINT: + { + sp_delta += (U32)index_imm->op_imm.bits; + }break; + case AD_IMM_ULONG: + { + sp_delta += (U64)index_imm->op_imm.bits; + }break; + } + } + } + } + } + + //- antoniom: fill+return + inst.size = 4; + inst.string = push_str8_copy(arena, str8_cstring(insn->decoded)); + inst.jump_dest_vaddr = rel_voff; + inst.flags = flags; + // TODO(antonio): pass sp_delta + + ArmadilloDone(&insn); + }break; //- rjf: x86/x64 disassembly case Arch_x86: @@ -555,6 +746,8 @@ ASYNC_WORK_DEF(dasm_parse_work) default:{}break; //- rjf: x86/x64 decoding + //- antoniom: arm64 decoding + case Arch_arm64: case Arch_x64: case Arch_x86: { diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index ff307b284..c8e7e7672 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -506,7 +506,22 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) // rjf: call => place spoof at return spot in stack, single-step after hitting else if(point->inst_flags & DASM_InstFlag_Call) { - flags |= (CTRL_TrapFlag_BeginSpoofMode|CTRL_TrapFlag_SingleStepAfterHit); + switch(arch) + { + default:{}break; + case Arch_arm32: + case Arch_x86: + {NotImplemented;}break; + + case Arch_x64: + { + flags |= (CTRL_TrapFlag_BeginSpoofMode|CTRL_TrapFlag_SingleStepAfterHit); + }break; + case Arch_arm64: + { + flags |= (CTRL_TrapFlag_SingleStepAfterHit); + }break; + } } // rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping @@ -526,7 +541,25 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) // rjf: push trap for natural linear flow if(good_line_info) { - CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max}; + CTRL_TrapFlags trap_flags = 0; + switch(arch) + { + default:{}break; + case Arch_arm32: + case Arch_x86: + {NotImplemented;}break; + + case Arch_x64: + { + trap_flags |= (CTRL_TrapFlag_EndStepping); + }break; + case Arch_arm64: + { + trap_flags |= (CTRL_TrapFlag_EndStepping | CTRL_TrapFlag_IgnoreStackPointerCheck); + }break; + } + + CTRL_Trap trap = {trap_flags, line_vaddr_rng.max}; ctrl_trap_list_push(arena, &result, &trap); } diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index d31d029e6..3a7b1485c 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -457,11 +457,12 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) { // rjf: find PE offset U32 pe_offset = 0; + PE_DosHeader dos_header = {0}; { - U64 dos_magic_off = base_vaddr; - U16 dos_magic = 0; - dmn_w32_process_read_struct(process, dos_magic_off, &dos_magic); - if(dos_magic == PE_DOS_MAGIC) + + dmn_w32_process_read_struct(process, base_vaddr, &dos_header); + + if(dos_header.magic == PE_DOS_MAGIC) { U64 pe_offset_off = base_vaddr + OffsetOf(PE_DosHeader, coff_file_offset); dmn_w32_process_read_struct(process, pe_offset_off, &pe_offset); @@ -472,10 +473,10 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) B32 got_coff_header = 0; U64 coff_header_off = 0; COFF_Header coff_header = {0}; + U32 pe_magic = 0; if(pe_offset > 0) { U64 pe_magic_off = base_vaddr + pe_offset; - U32 pe_magic = 0; dmn_w32_process_read_struct(process, pe_magic_off, &pe_magic); if(pe_magic == PE_MAGIC) { @@ -487,12 +488,16 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) } } + // rjf: get arch and size + B32 got_size = 0; + U32 size = 0; + Arch arch = Arch_Null; DMN_W32_ImageInfo result = zero_struct; + if(got_coff_header) { U64 optional_size_off = 0; - Arch arch = Arch_Null; switch(coff_header.machine) { case COFF_MachineType_X86: @@ -505,20 +510,97 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) arch = Arch_x64; optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image); }break; + case COFF_MachineType_ARM64: + { + arch = Arch_arm64; + optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image); + }break; default: {}break; } if(arch != Arch_Null) { U64 optional_off = coff_header_off + sizeof(coff_header); - U32 size = 0; if(dmn_w32_process_read_struct(process, optional_off+optional_size_off, &size) >= sizeof(size)) { - result.arch = arch; - result.size = size; + got_size = 1; } } } + + // antoniom: ARM64EC detection + if(got_size) + { + Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr+size); + U32 opt_ext_size = coff_header.optional_header_size; + Rng1U64 opt_ext_off_range = r1u64(coff_header_off + sizeof(coff_header), + coff_header_off + sizeof(coff_header) + opt_ext_size); + + if(opt_ext_size > 0) + { + U16 opt_ext_magic = 0; + dmn_w32_process_read_struct(process, opt_ext_off_range.min, &opt_ext_magic); + + U32 reported_data_dir_offset = 0; + U32 reported_data_dir_count = 0; + switch(opt_ext_magic) + { + case PE_PE32_MAGIC: + { + PE_OptionalHeader32 pe_optional = {0}; + dmn_w32_process_read_struct(process, opt_ext_off_range.min, &pe_optional); + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + case PE_PE32PLUS_MAGIC: + { + PE_OptionalHeader32Plus pe_optional = {0}; + dmn_w32_process_read_struct(process, opt_ext_off_range.min, &pe_optional); + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + } + + U32 data_dir_max = (opt_ext_size - reported_data_dir_offset) / sizeof(PE_DataDirectory); + U32 data_dir_count = ClampTop(reported_data_dir_count, data_dir_max); + + if (PE_DataDirectoryIndex_LOAD_CONFIG < data_dir_count) + { + U64 dir_offset = opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_LOAD_CONFIG; + PE_DataDirectory data_dir = {0}; + dmn_w32_process_read_struct(process, dir_offset, &data_dir); + + PE_LoadConfig64 load_config_header = {0}; + switch(opt_ext_magic) + { + case PE_PE32PLUS_MAGIC: + { + dmn_w32_process_read_struct(process, vaddr_range.min + data_dir.virt_off, &load_config_header); + }break; + case PE_PE32_MAGIC: + { + // TODO(antoniom): just get the size and chpe metadata pointer + PE_LoadConfig32 load_config_header32 = {0}; + dmn_w32_process_read_struct(process, vaddr_range.min + data_dir.virt_off, &load_config_header32); + load_config_header.size = load_config_header32.size; + load_config_header.chpe_metadata_ptr = load_config_header32.chpe_metadata_ptr; + }break; + } + + if(load_config_header.size >= OffsetOf(PE_LoadConfig64, chpe_metadata_ptr) && + load_config_header.chpe_metadata_ptr != 0) + { + arch = Arch_arm64; + } + } + } + } + + if (got_size) + { + result.arch = arch; + result.size = size; + } return result; } @@ -589,9 +671,92 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) case Arch_Null: case Arch_COUNT: {}break; - case Arch_arm64: case Arch_arm32: {NotImplemented;}break; + + //////////////////////////// + //- antoniom: arm64 + // + case Arch_arm64: + { + Temp scratch = scratch_begin(0, 0); + + REGS_RegBlockARM64 *dst = (REGS_RegBlockARM64 *)reg_block; + + DMN_W32_Context_arm64 *ctx = 0; + U32 ctx_flags = DMN_W32_CTX_ARM64_ALL; + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + DWORD error = GetLastError(); + if (error = ERROR_INSUFFICIENT_BUFFER){ + void *ctx_memory = push_array(scratch.arena, U8, size); + if (!InitializeContext(ctx_memory, ctx_flags, (CONTEXT **) &ctx, &size)) + { + ctx = 0; + } + } + + //- antoniom: get thread context + if(!GetThreadContext(thread, (CONTEXT *)ctx)) + { + ctx = 0; + } + + if (ctx == 0) + { + break; + } + result = 1; + + //- antoniom: Convert CONTEXT -> REGS_RegBlockARM64 + dst->pc.u64 = ctx->Pc; + dst->context_flags.u32 = ctx->ContextFlags; + + dst->cpsr.u32 = ctx->Cpsr; + dst->fpcr.u32 = ctx->Fpcr; + dst->fpsr.u32 = ctx->Fpsr; + dst->bcr0.u32 = ctx->Bcr[0]; + dst->bcr1.u32 = ctx->Bcr[1]; + dst->bcr2.u32 = ctx->Bcr[2]; + dst->bcr3.u32 = ctx->Bcr[3]; + dst->bcr4.u32 = ctx->Bcr[4]; + dst->bcr5.u32 = ctx->Bcr[5]; + dst->bcr6.u32 = ctx->Bcr[6]; + dst->bcr7.u32 = ctx->Bcr[7]; + dst->bvr0.u64 = ctx->Bvr[0]; + dst->bvr1.u64 = ctx->Bvr[1]; + dst->bvr2.u64 = ctx->Bvr[2]; + dst->bvr3.u64 = ctx->Bvr[3]; + dst->bvr4.u64 = ctx->Bvr[4]; + dst->bvr5.u64 = ctx->Bvr[5]; + dst->bvr6.u64 = ctx->Bvr[6]; + dst->bvr7.u64 = ctx->Bvr[7]; + dst->wcr0.u32 = ctx->Wcr[0]; + dst->wcr1.u32 = ctx->Wcr[1]; + dst->wvr0.u64 = ctx->Wvr[0]; + dst->wvr1.u64 = ctx->Wvr[1]; + + REGS_Reg64 *x_d = &dst->x0; + DWORD64 *x_s = &ctx->X[0]; + for (DWORD i = 0; + i < 31; + i += 1, x_d += 1, x_s += 1){ + x_d->u64 = *x_s; + } + + REGS_Reg128 *v_d = &dst->v0; + REGS_Reg128 *v_s = (REGS_Reg128*) &ctx->V[0]; + for (DWORD i = 0; + i < 32; + i += 1, v_d += 1, v_s += 1){ + v_d->u64[0] = v_s->u64[0]; + v_d->u64[1] = v_s->u64[1]; + } + + dst->x31.u64 = ctx->Sp; + + scratch_end(scratch); + }break; //////////////////////////// //- rjf: x86 @@ -685,18 +850,18 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) REGS_RegBlockX64 *dst = (REGS_RegBlockX64 *)reg_block; //- rjf: unpack info about available features - U32 feature_mask = GetEnabledXStateFeatures(); + U32 feature_mask = dmn_w32_GetEnabledXStateFeatures(); B32 xstate_enabled = (feature_mask & (XSTATE_MASK_AVX | XSTATE_MASK_AVX512)) != 0; //- rjf: set up context - CONTEXT *ctx = 0; + DMN_W32_Context_x64 *ctx = 0; U32 ctx_flags = DMN_W32_CTX_X64_ALL | (xstate_enabled ? DMN_W32_CTX_INTEL_XSTATE : 0); DWORD size = 0; InitializeContext(0, ctx_flags, 0, &size); if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { void *ctx_memory = push_array(scratch.arena, U8, size); - if(!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)) + if(!InitializeContext(ctx_memory, ctx_flags, (CONTEXT **) &ctx, &size)) { ctx = 0; } @@ -705,11 +870,11 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) //- rjf: unpack features available on this context if (xstate_enabled) { - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX | XSTATE_MASK_AVX512); + dmn_w32_SetXStateFeaturesMask((CONTEXT *) ctx, XSTATE_MASK_AVX | XSTATE_MASK_AVX512); } //- rjf: get thread context - if(!GetThreadContext(thread, ctx)) + if(!GetThreadContext(thread, (CONTEXT *) ctx)) { ctx = 0; } @@ -722,7 +887,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) result = 1; DWORD64 xstate_mask = 0; - GetXStateFeaturesMask(ctx, &xstate_mask); + dmn_w32_GetXStateFeaturesMask((CONTEXT *) ctx, &xstate_mask); //- rjf: convert context -> REGS_RegBlockX64 XSAVE_FORMAT *xsave = &ctx->FltSave; @@ -791,7 +956,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) if(xstate_mask & XSTATE_MASK_AVX) { DWORD avx_length = 0; - U8* avx_s = (U8*)LocateXStateFeature(ctx, XSTATE_AVX, &avx_length); + U8* avx_s = (U8*)dmn_w32_LocateXStateFeature((CONTEXT * )ctx, XSTATE_AVX, &avx_length); Assert(avx_length == 16 * sizeof(REGS_Reg128)); REGS_Reg512 *zmm_d = &dst->zmm0; @@ -813,7 +978,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) if(xstate_mask & XSTATE_MASK_AVX512) { DWORD kmask_length = 0; - U64* kmask_s = (U64*)LocateXStateFeature(ctx, XSTATE_AVX512_KMASK, &kmask_length); + U64* kmask_s = (U64*)dmn_w32_LocateXStateFeature((CONTEXT *) ctx, XSTATE_AVX512_KMASK, &kmask_length); Assert(kmask_length == 8 * sizeof(U64)); REGS_Reg64 *kmask_d = &dst->k0; @@ -823,7 +988,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) } DWORD avx512h_length = 0; - U8* avx512h_s = (U8*)LocateXStateFeature(ctx, XSTATE_AVX512_ZMM_H, &avx512h_length); + U8* avx512h_s = (U8*)dmn_w32_LocateXStateFeature((CONTEXT *) ctx, XSTATE_AVX512_ZMM_H, &avx512h_length); Assert(avx512h_length == 16 * sizeof(REGS_Reg256)); REGS_Reg512 *zmmh_d = &dst->zmm0; @@ -833,7 +998,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) } DWORD avx512_length = 0; - U8* avx512_s = (U8*)LocateXStateFeature(ctx, XSTATE_AVX512_ZMM, &avx512_length); + U8* avx512_s = (U8*)dmn_w32_LocateXStateFeature((CONTEXT *) ctx, XSTATE_AVX512_ZMM, &avx512_length); Assert(avx512_length == 16 * sizeof(REGS_Reg512)); REGS_Reg512 *zmm_d = &dst->zmm16; @@ -883,9 +1048,95 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) case Arch_Null: case Arch_COUNT: {}break; - case Arch_arm64: case Arch_arm32: {NotImplemented;}break; + + //////////////////////////// + //- antoniom: arm64 + // + case Arch_arm64: + { + Temp scratch = scratch_begin(0, 0); + REGS_RegBlockARM64 *src = (REGS_RegBlockARM64 *) reg_block; + + //- antoniom: set up context + DMN_W32_Context_arm64 *ctx = 0; + U32 ctx_flags = DMN_W32_CTX_ARM64_ALL; + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + void *ctx_memory = push_array(scratch.arena, U8, size); + if(!InitializeContext(ctx_memory, ctx_flags, (CONTEXT **) &ctx, &size)) + { + ctx = 0; + } + } + + //- antoniom: bad context -> abort + if(ctx == 0) + { + DWORD error = GetLastError(); + break; + } + + //- antoniom: convert REGS_RegBlockARM64 -> CONTEXT + ctx->ContextFlags = src->context_flags.u32; + ctx->Cpsr = src->cpsr.u32; + ctx->Fpcr = src->fpcr.u32; + ctx->Fpsr = src->fpsr.u32; + + ctx->Cpsr = src->cpsr.u32; + ctx->Fpcr = src->fpcr.u32; + ctx->Fpsr = src->fpsr.u32; + ctx->Bcr[0] = src->bcr0.u32; + ctx->Bcr[1] = src->bcr1.u32; + ctx->Bcr[2] = src->bcr2.u32; + ctx->Bcr[3] = src->bcr3.u32; + ctx->Bcr[4] = src->bcr4.u32; + ctx->Bcr[5] = src->bcr5.u32; + ctx->Bcr[6] = src->bcr6.u32; + ctx->Bcr[7] = src->bcr7.u32; + ctx->Bvr[0] = src->bvr0.u64; + ctx->Bvr[1] = src->bvr1.u64; + ctx->Bvr[2] = src->bvr2.u64; + ctx->Bvr[3] = src->bvr3.u64; + ctx->Bvr[4] = src->bvr4.u64; + ctx->Bvr[5] = src->bvr5.u64; + ctx->Bvr[6] = src->bvr6.u64; + ctx->Bvr[7] = src->bvr7.u64; + ctx->Wcr[0] = src->wcr0.u32; + ctx->Wcr[1] = src->wcr1.u32; + ctx->Wvr[0] = src->wvr0.u64; + ctx->Wvr[1] = src->wvr1.u64; + + DWORD64 *x_d = &ctx->X[0]; + REGS_Reg64 *x_s = &src->x0; + for (DWORD i = 0; + i < 31; + i += 1, x_d += 1, x_s += 1){ + *x_d = x_s->u64; + } + + REGS_Reg128 *v_d = (REGS_Reg128*) &ctx->V[0]; + REGS_Reg128 *v_s = &src->v0; + for (DWORD i = 0; + i < 32; + i += 1, v_d += 1, v_s += 1){ + v_d->u64[0] = v_s->u64[0]; + v_d->u64[1] = v_s->u64[1]; + } + + ctx->Sp = src->x31.u64; + ctx->Pc = src->pc.u64; + + //- antoniom: set thread context + if(SetThreadContext(thread, (CONTEXT *) ctx)) + { + result = 1; + } + scratch_end(scratch); + }break; //////////////////////////// //- rjf: x86 @@ -964,18 +1215,18 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) REGS_RegBlockX64 *src = (REGS_RegBlockX64 *)reg_block; //- rjf: unpack info about available features - U32 feature_mask = GetEnabledXStateFeatures(); + U32 feature_mask = dmn_w32_GetEnabledXStateFeatures(); B32 xstate_enabled = (feature_mask & (XSTATE_MASK_AVX | XSTATE_MASK_AVX512)) != 0; //- rjf: set up context - CONTEXT *ctx = 0; + DMN_W32_Context_x64 *ctx = 0; U32 ctx_flags = DMN_W32_CTX_X64_ALL | (xstate_enabled ? DMN_W32_CTX_INTEL_XSTATE : 0); DWORD size = 0; InitializeContext(0, ctx_flags, 0, &size); if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { void *ctx_memory = push_array(scratch.arena, U8, size); - if(!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)) + if(!InitializeContext(ctx_memory, ctx_flags, (CONTEXT **) &ctx, &size)) { ctx = 0; } @@ -984,7 +1235,7 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) //- rjf: unpack features available on this context if (xstate_enabled) { - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX | XSTATE_MASK_AVX512); + dmn_w32_SetXStateFeaturesMask((CONTEXT *)ctx, XSTATE_MASK_AVX | XSTATE_MASK_AVX512); } //- rjf: bad context -> abort @@ -1058,7 +1309,7 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) if(feature_mask & XSTATE_MASK_AVX) { DWORD avx_length = 0; - U8* avx_d = (U8*)LocateXStateFeature(ctx, XSTATE_AVX, &avx_length); + U8* avx_d = (U8*)dmn_w32_LocateXStateFeature((CONTEXT *) ctx, XSTATE_AVX, &avx_length); Assert(avx_length == 16 * sizeof(REGS_Reg128)); REGS_Reg512 *zmm_s = &src->zmm0; @@ -1072,7 +1323,7 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) if(feature_mask & XSTATE_MASK_AVX512) { DWORD kmask_length = 0; - U64* kmask_d = (U64*)LocateXStateFeature(ctx, XSTATE_AVX512_KMASK, &kmask_length); + U64* kmask_d = (U64*)dmn_w32_LocateXStateFeature((CONTEXT *) ctx, XSTATE_AVX512_KMASK, &kmask_length); Assert(kmask_length == 8 * sizeof(*kmask_d)); REGS_Reg64 *kmask_s = &src->k0; @@ -1082,7 +1333,7 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) } DWORD avx512h_length = 0; - U8* avx512h_d = (U8*)LocateXStateFeature(ctx, XSTATE_AVX512_ZMM_H, &avx512h_length); + U8* avx512h_d = (U8*)dmn_w32_LocateXStateFeature((CONTEXT *) ctx, XSTATE_AVX512_ZMM_H, &avx512h_length); Assert(avx512h_length == 16 * sizeof(REGS_Reg256)); REGS_Reg512 *zmmh_s = &src->zmm0; @@ -1092,7 +1343,7 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) } DWORD avx512_length = 0; - U8* avx512_d = (U8*)LocateXStateFeature(ctx, XSTATE_AVX512_ZMM, &avx512_length); + U8* avx512_d = (U8*)dmn_w32_LocateXStateFeature((CONTEXT *) ctx, XSTATE_AVX512_ZMM, &avx512_length); Assert(avx512_length == 16 * sizeof(REGS_Reg512)); REGS_Reg512 *zmm_s = &src->zmm16; @@ -1103,7 +1354,7 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) } //- rjf: set thread context - if(SetThreadContext(thread, ctx)) + if(SetThreadContext(thread, (CONTEXT *) ctx)) { result = 1; } @@ -1148,7 +1399,14 @@ dmn_init(void) // rjf: load Windows 10+ GetThreadDescription API { - dmn_w32_GetThreadDescription = (DMN_W32_GetThreadDescriptionFunctionType *)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "GetThreadDescription"); + HMODULE dll_handle = GetModuleHandleA("Kernel32.dll"); + dmn_w32_GetThreadDescription = (DMN_W32_GetThreadDescriptionFunctionType *)GetProcAddress(dll_handle, "GetThreadDescription"); + dmn_w32_LocateXStateFeature = (DMN_W32_LocateXStateFeatureFunctionType *)GetProcAddress(dll_handle, "LocateXStateFeature"); + dmn_w32_SetXStateFeaturesMask = (DMN_W32_SetXStateFeaturesMaskFunctionType *)GetProcAddress(dll_handle, "SetXStateFeaturesMask"); + + void *get_enabled_xstate_features_proc = GetProcAddress(dll_handle, "GetEnabledXStateFeatures"); + dmn_w32_GetEnabledXStateFeatures = get_enabled_xstate_features_proc ? (DMN_W32_GetEnabledXStateFeaturesFunctionType *) get_enabled_xstate_features_proc : dmn_w32_stub_GetEnabledXStateFeatures; + } // rjf: setup environment variables @@ -1344,7 +1602,7 @@ dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid) struct JIT_DEBUG_INFO { DWORD dwSize; - DWORD dwProcessorArchitecture; + DWORD dwProcessorArch; DWORD dwThreadID; DWORD dwReserved0; ULONG64 lpExceptionAddress; @@ -1478,7 +1736,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) ////////////////////////// //- rjf: get single step thread's context (x64 single-step-set fast path) // - CONTEXT *single_step_thread_ctx = 0; + void *single_step_thread_ctx = 0; if(!dmn_handle_match(ctrls->single_step_thread, dmn_handle_zero())) { DMN_W32_Entity *thread = dmn_w32_entity_from_handle(ctrls->single_step_thread); @@ -1488,13 +1746,28 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) default:{}break; case Arch_x64: { + DMN_W32_Context_x64 *x64_ctx = (DMN_W32_Context_x64 *) single_step_thread_ctx; U32 ctx_flags = DMN_W32_CTX_X64|DMN_W32_CTX_INTEL_CONTROL; DWORD size = 0; InitializeContext(0, ctx_flags, 0, &size); if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { void *ctx_memory = push_array(scratch.arena, U8, size); - if(!InitializeContext(ctx_memory, ctx_flags, &single_step_thread_ctx, &size)) + if(!InitializeContext(ctx_memory, ctx_flags, (CONTEXT **) &x64_ctx, &size)) + { + single_step_thread_ctx = 0; + } + } + }break; + case Arch_arm64: + { + U32 ctx_flags = DMN_W32_CTX_ARM64|DMN_W32_CTX_ARM64_CONTROL; + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + void *ctx_memory = push_array(scratch.arena, U8, size); + if(!InitializeContext(ctx_memory, ctx_flags, (CONTEXT **) &single_step_thread_ctx, &size)) { single_step_thread_ctx = 0; } @@ -1516,9 +1789,24 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) case Arch_Null: case Arch_COUNT: {}break; - case Arch_arm64: case Arch_arm32: {NotImplemented;}break; + + case Arch_arm64: + { + DMN_W32_Context_arm64 *arm64_ctx = (DMN_W32_Context_arm64 *)single_step_thread_ctx; + if(!GetThreadContext(thread->handle, (CONTEXT *) arm64_ctx)) + { + single_step_thread_ctx = 0; + } + if(arm64_ctx != 0) + { + U64 new_cpsr = arm64_ctx->Cpsr | 0x200000; + arm64_ctx->Cpsr = new_cpsr; + SetThreadContext(thread->handle, (CONTEXT *) arm64_ctx); + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); + } + }break; //- rjf: x86 case Arch_x86: @@ -1532,16 +1820,17 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) //- rjf: x64 case Arch_x64: { - if(!GetThreadContext(thread->handle, single_step_thread_ctx)) + DMN_W32_Context_x64 *x64_ctx = (DMN_W32_Context_x64 *) single_step_thread_ctx; + if(!GetThreadContext(thread->handle, (CONTEXT *) x64_ctx)) { single_step_thread_ctx = 0; } - if(single_step_thread_ctx != 0) + if(x64_ctx != 0) { - U64 rflags = single_step_thread_ctx->EFlags|0x2; + U64 rflags = x64_ctx->EFlags|0x2; U64 new_rflags = rflags | 0x100; - single_step_thread_ctx->EFlags = new_rflags; - SetThreadContext(thread->handle, single_step_thread_ctx); + x64_ctx->EFlags = new_rflags; + SetThreadContext(thread->handle, (CONTEXT *) x64_ctx); ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); } }break; @@ -1551,7 +1840,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) ////////////////////////// //- rjf: write all traps into memory // - U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, ctrls->traps.trap_count); + //- antoniom: ARM64 trap is 4 bytes, so assume worst case for simplicity + U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, ctrls->traps.trap_count * 4); ProfScope("write all traps into memory") { U64 trap_idx = 0; @@ -1560,10 +1850,49 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, trap_idx += 1) { DMN_Trap *trap = n->v+n_idx; - trap_swap_bytes[trap_idx] = 0xCC; - dmn_process_read(trap->process, r1u64(trap->vaddr, trap->vaddr+1), trap_swap_bytes+trap_idx); - U8 int3 = 0xCC; - dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &int3); + DMN_W32_Entity *trap_process = dmn_w32_entity_from_handle(trap->process); + + Arch arch = trap_process->arch; +#if 0 + for(DMN_W32_Entity *child = trap_process->first; child != &dmn_w32_entity_nil; child = child->next) + { + if(child->kind == DMN_W32_EntityKind_Module) + { + if(contains_1u64(child->module.vaddr_range, trap->vaddr)) + { + arch = child->arch; + break; + } + } + } +#endif + switch(arch) + { + case Arch_Null: + case Arch_COUNT: + {}break; + case Arch_arm32: + {NotImplemented;}break; + + //- rjf: x86/x64 + case Arch_x64: + case Arch_x86: + { + trap_swap_bytes[trap_idx] = 0xCC; + dmn_process_read(trap->process, r1u64(trap->vaddr, trap->vaddr+1), trap_swap_bytes+trap_idx); + U8 int3 = 0xCC; + dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &int3); + }break; + + //- antoniom: arm64 + case Arch_arm64: + { + U32 *trap_swap_u32 = (U32*)(trap_swap_bytes + trap_idx*4); + dmn_process_read(trap->process, r1u64(trap->vaddr, trap->vaddr+4), trap_swap_bytes+trap_idx*4); + U32 brk0x4000 = 0xd43e0000; + dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+4), &brk0x4000); + }break; + } } } } @@ -1780,7 +2109,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) thread->arch = image_info.arch; thread->thread.thread_local_base = tls_base; module->handle = module_handle; - module->module.vaddr_range = r1u64(module_base, image_info.size); + module->arch = image_info.arch; + module->module.vaddr_range = r1u64(module_base, module_base+image_info.size); module->module.is_main = 1; module->module.address_of_name_pointer = module_name_vaddr; module->module.name_is_unicode = module_name_is_unicode; @@ -1793,8 +2123,30 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) // generate debug events) { U8 injection_code[DMN_W32_INJECTED_CODE_SIZE]; - MemorySet(injection_code, 0xCC, DMN_W32_INJECTED_CODE_SIZE); - injection_code[0] = 0xC3; + + switch(image_info.arch) + { + default: {}break; + case Arch_x64: + case Arch_x86: + { + MemorySet(injection_code, 0xCC, DMN_W32_INJECTED_CODE_SIZE); + injection_code[0] = 0xC3; + }break; + case Arch_arm64: + { + U32 *injection_code_u32 = (U32*)injection_code; + + //- antoniom: ret + injection_code_u32[0] = 0xd65f03c0; + for(U32 idx = 1; idx < sizeof(injection_code) / sizeof(U32); idx += 1) + { + //- antoniom: brk #0xf000 + injection_code_u32[idx] = 0xd43e0000; + } + }break; + } + U64 injection_size = DMN_W32_INJECTED_CODE_SIZE + sizeof(DMN_W32_InjectedBreak); U64 injection_address = (U64)VirtualAllocEx(process_handle, 0, injection_size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE); dmn_w32_process_write(process_handle, r1u64(injection_address, injection_address+sizeof(injection_code)), injection_code); @@ -2108,10 +2460,12 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) B32 hit_explicit_trap = 0; if(is_trap && !hit_user_trap) { - U8 instruction_byte = 0; - if(dmn_w32_process_read_struct(process->handle, instruction_pointer, &instruction_byte)) + U32 instruction_u32 = 0; + if(dmn_w32_process_read_struct(process->handle, instruction_pointer, &instruction_u32)) { - hit_explicit_trap = (instruction_byte == 0xCC || instruction_byte == 0xCD); + hit_explicit_trap = ((instruction_u32 & 0xff) == 0xCC || + (instruction_u32 & 0xff) == 0xCD || + instruction_u32 == 0xd43e0000); } } @@ -2140,28 +2494,28 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) //- rjf: x64 (fastpath) case Arch_x64: { - CONTEXT *ctx = 0; + DMN_W32_Context_x64 *x64_ctx = 0; U32 ctx_flags = DMN_W32_CTX_X64|DMN_W32_CTX_INTEL_CONTROL; DWORD size = 0; InitializeContext(0, ctx_flags, 0, &size); if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { void *ctx_memory = push_array(scratch.arena, U8, size); - if(!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)) + if(!InitializeContext(ctx_memory, ctx_flags, (CONTEXT **) &x64_ctx, &size)) { ctx = 0; } } - if(!GetThreadContext(thread->handle, ctx)) + if(!GetThreadContext(thread->handle, (CONTEXT *) x64_ctx)) { - ctx = 0; + x64_ctx = 0; } - if(ctx != 0) + if(x64_ctx != 0) { - U64 rip = ctx->Rip; + U64 rip = x64_ctx->Rip; U64 new_rip = instruction_pointer; - ctx->Rip = new_rip; - SetThreadContext(thread->handle, ctx); + x64_ctx->Rip = new_rip; + SetThreadContext(thread->handle, (CONTEXT *) x64_ctx); ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); } }break; @@ -2481,10 +2835,35 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, trap_idx += 1) { DMN_Trap *trap = n->v+n_idx; - U8 og_byte = trap_swap_bytes[trap_idx]; - if(og_byte != 0xCC) + DMN_W32_Entity *trap_process = dmn_w32_entity_from_handle(trap->process); + Arch arch = trap_process->arch; + + switch(arch) { - dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &og_byte); + case Arch_Null: + case Arch_COUNT: + {}break; + case Arch_arm32: + {NotImplemented;}break; + + case Arch_x86: + case Arch_x64: + { + U8 og_byte = trap_swap_bytes[trap_idx]; + if(og_byte != 0xCC) + { + dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &og_byte); + } + }break; + + case Arch_arm64: + { + U32 og_u32 = *((U32*) (trap_swap_bytes+trap_idx*4)); + if(og_u32 != 0xd43e0000) + { + dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+4), &og_u32); + } + }break; } } } @@ -2503,9 +2882,17 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) case Arch_Null: case Arch_COUNT: {}break; - case Arch_arm64: case Arch_arm32: {NotImplemented;}break; + + //- antoniom: arm64 + case Arch_arm64: + { + REGS_RegBlockARM64 regs = {0}; + dmn_thread_read_reg_block(ctrls->single_step_thread, ®s); + regs.cpsr.u32 &= ~0x200000; + dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); + }break; //- rjf: x86/64 case Arch_x86: @@ -2517,16 +2904,17 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) }break; case Arch_x64: { - if(!GetThreadContext(thread->handle, single_step_thread_ctx)) + DMN_W32_Context_x64 *x64_ctx = (DMN_W32_Context_x64 *) single_step_thread_ctx; + if(!GetThreadContext(thread->handle, (CONTEXT *) x64_ctx)) { single_step_thread_ctx = 0; } - if(ctx != 0) + if(x64_ctx != 0) { - U64 rflags = single_step_thread_ctx->EFlags|0x2; + U64 rflags = x64_ctx->EFlags|0x2; U64 new_rflags = rflags & ~0x100; - single_step_thread_ctx->EFlags = new_rflags; - SetThreadContext(thread->handle, single_step_thread_ctx); + x64_ctx->EFlags = new_rflags; + SetThreadContext(thread->handle, (CONTEXT *) x64_ctx); ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); } }break; @@ -2797,9 +3185,10 @@ dmn_stack_base_vaddr_from_thread(DMN_Handle handle) case Arch_Null: case Arch_COUNT: {}break; - case Arch_arm64: case Arch_arm32: {NotImplemented;}break; + + case Arch_arm64: case Arch_x64: { U64 stack_base_addr = tlb + 0x8; @@ -2831,9 +3220,10 @@ dmn_tls_root_vaddr_from_thread(DMN_Handle handle) case Arch_Null: case Arch_COUNT: {}break; - case Arch_arm64: case Arch_arm32: {NotImplemented;}break; + + case Arch_arm64: case Arch_x64: { result += 88; diff --git a/src/demon/win32/demon_core_win32.h b/src/demon/win32/demon_core_win32.h index c72345711..8c5ce3d2a 100644 --- a/src/demon/win32/demon_core_win32.h +++ b/src/demon/win32/demon_core_win32.h @@ -62,6 +62,7 @@ #define DMN_W32_CTX_X86 0x00010000 #define DMN_W32_CTX_X64 0x00100000 +#define DMN_W32_CTX_ARM64 0x00400000 #define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags #define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15 @@ -80,6 +81,151 @@ DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \ DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_FLOATS | \ DMN_W32_CTX_INTEL_DEBUG) +#define DMN_W32_CTX_ARM64_CONTROL 0x0001 +#define DMN_W32_CTX_ARM64_INTEGER 0x0002 +#define DMN_W32_CTX_ARM64_FLOATING_POINT 0x0004 +#define DMN_W32_CTX_ARM64_DEBUG 0x0008 +#define DMN_W32_CTX_ARM64_X18 0x0010 + +#define DMN_W32_CTX_ARM64_ALL (DMN_W32_CTX_ARM64 |\ +DMN_W32_CTX_ARM64_CONTROL | DMN_W32_CTX_ARM64_INTEGER | \ +DMN_W32_CTX_ARM64_FLOATING_POINT | DMN_W32_CTX_ARM64_DEBUG | \ +DMN_W32_CTX_ARM64_X18) + + +//////////////////////////////// +//~ antoniom: Win32 Demon Contexts + +typedef struct DMN_W32_Context_arm64 DMN_W32_Context_arm64; +struct DMN_W32_Context_arm64 +{ + DWORD ContextFlags; + DWORD Cpsr; + union { + struct { + DWORD64 X0; + DWORD64 X1; + DWORD64 X2; + DWORD64 X3; + DWORD64 X4; + DWORD64 X5; + DWORD64 X6; + DWORD64 X7; + DWORD64 X8; + DWORD64 X9; + DWORD64 X10; + DWORD64 X11; + DWORD64 X12; + DWORD64 X13; + DWORD64 X14; + DWORD64 X15; + DWORD64 X16; + DWORD64 X17; + DWORD64 X18; + DWORD64 X19; + DWORD64 X20; + DWORD64 X21; + DWORD64 X22; + DWORD64 X23; + DWORD64 X24; + DWORD64 X25; + DWORD64 X26; + DWORD64 X27; + DWORD64 X28; + DWORD64 Fp; + DWORD64 Lr; + } DUMMYSTRUCTNAME; + DWORD64 X[31]; + } DUMMYUNIONNAME; + DWORD64 Sp; + DWORD64 Pc; + REGS_Reg128 V[32]; + DWORD Fpcr; + DWORD Fpsr; + DWORD Bcr[8]; + DWORD64 Bvr[8]; + DWORD Wcr[2]; + DWORD64 Wvr[2]; +}; + +typedef XSAVE_FORMAT XMM_SAVE_AREA32; +typedef struct DMN_W32_Context_x64 DMN_W32_Context_x64; +struct DMN_W32_Context_x64 +{ + DWORD64 P1Home; + DWORD64 P2Home; + DWORD64 P3Home; + DWORD64 P4Home; + DWORD64 P5Home; + DWORD64 P6Home; + DWORD ContextFlags; + DWORD MxCsr; + WORD SegCs; + WORD SegDs; + WORD SegEs; + WORD SegFs; + WORD SegGs; + WORD SegSs; + DWORD EFlags; + DWORD64 Dr0; + DWORD64 Dr1; + DWORD64 Dr2; + DWORD64 Dr3; + DWORD64 Dr6; + DWORD64 Dr7; + DWORD64 Rax; + DWORD64 Rcx; + DWORD64 Rdx; + DWORD64 Rbx; + DWORD64 Rsp; + DWORD64 Rbp; + DWORD64 Rsi; + DWORD64 Rdi; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 Rip; + union { + XMM_SAVE_AREA32 FltSave; + // NOTE(antoniom): ARM64-define + // NEON128 Q[16]; + ULONGLONG D[32]; + struct { + M128A Header[2]; + M128A Legacy[8]; + M128A Xmm0; + M128A Xmm1; + M128A Xmm2; + M128A Xmm3; + M128A Xmm4; + M128A Xmm5; + M128A Xmm6; + M128A Xmm7; + M128A Xmm8; + M128A Xmm9; + M128A Xmm10; + M128A Xmm11; + M128A Xmm12; + M128A Xmm13; + M128A Xmm14; + M128A Xmm15; + } DUMMYSTRUCTNAME; + DWORD S[32]; + } DUMMYUNIONNAME; + M128A VectorRegister[26]; + DWORD64 VectorControl; + DWORD64 DebugControl; + DWORD64 LastBranchToRip; + DWORD64 LastBranchFromRip; + DWORD64 LastExceptionToRip; + DWORD64 LastExceptionFromRip; +}; + //////////////////////////////// //~ rjf: Per-Entity State @@ -180,8 +326,11 @@ struct DMN_W32_ImageInfo //////////////////////////////// //~ rjf: Dynamically-Loaded Win32 Function Types - typedef HRESULT DMN_W32_GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription); +typedef VOID *DMN_W32_LocateXStateFeatureFunctionType(CONTEXT *Context, DWORD FeatureId, DWORD *Length); +typedef BOOL DMN_W32_SetXStateFeaturesMaskFunctionType(CONTEXT *Context, DWORD64 FeatureMask); +typedef BOOL DMN_W32_GetXStateFeaturesMaskFunctionType(CONTEXT *Context, DWORD64 *FeatureMask); +typedef DWORD64 DMN_W32_GetEnabledXStateFeaturesFunctionType(void); //////////////////////////////// //~ rjf: Shared State Bundle @@ -231,10 +380,17 @@ struct DMN_W32_Shared //////////////////////////////// //~ rjf: Globals +// + +DWORD64 dmn_w32_stub_GetEnabledXStateFeatures(void) { return(0); } global DMN_W32_Shared *dmn_w32_shared = 0; global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil}; global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0; +global DMN_W32_LocateXStateFeatureFunctionType *dmn_w32_LocateXStateFeature = 0; +global DMN_W32_SetXStateFeaturesMaskFunctionType *dmn_w32_SetXStateFeaturesMask = 0; +global DMN_W32_GetXStateFeaturesMaskFunctionType *dmn_w32_GetXStateFeaturesMask = 0; +global DMN_W32_GetEnabledXStateFeaturesFunctionType *dmn_w32_GetEnabledXStateFeatures = 0; thread_static B32 dmn_w32_ctrl_thread = 0; //////////////////////////////// diff --git a/src/lib_rdi_format/rdi_format.c b/src/lib_rdi_format/rdi_format.c index 4e79ae5ee..440b2c8ee 100644 --- a/src/lib_rdi_format/rdi_format.c +++ b/src/lib_rdi_format/rdi_format.c @@ -231,6 +231,7 @@ switch(arch) default:{}break; case RDI_Arch_X86:{result = 4;}break; case RDI_Arch_X64:{result = 8;}break; +case RDI_Arch_ARM64:{result = 8;}break; } return result; } diff --git a/src/lib_rdi_format/rdi_format.h b/src/lib_rdi_format/rdi_format.h index f440f03c6..e72e339bf 100644 --- a/src/lib_rdi_format/rdi_format.h +++ b/src/lib_rdi_format/rdi_format.h @@ -112,6 +112,7 @@ typedef enum RDI_ArchEnum RDI_Arch_NULL = 0, RDI_Arch_X86 = 1, RDI_Arch_X64 = 2, +RDI_Arch_ARM64 = 3, } RDI_ArchEnum; typedef RDI_U8 RDI_RegCode; @@ -292,6 +293,101 @@ RDI_RegCodeX64_fdp = 99, RDI_RegCodeX64_mxcsr_mask = 100, } RDI_RegCodeX64Enum; +typedef RDI_U8 RDI_RegCodeARM64; +typedef enum RDI_RegCodeARM64Enum +{ +RDI_RegCodeARM64_nil = 0, +RDI_RegCodeARM64_x0 = 1, +RDI_RegCodeARM64_x1 = 2, +RDI_RegCodeARM64_x2 = 3, +RDI_RegCodeARM64_x3 = 4, +RDI_RegCodeARM64_x4 = 5, +RDI_RegCodeARM64_x5 = 6, +RDI_RegCodeARM64_x6 = 7, +RDI_RegCodeARM64_x7 = 8, +RDI_RegCodeARM64_x8 = 9, +RDI_RegCodeARM64_x9 = 10, +RDI_RegCodeARM64_x10 = 11, +RDI_RegCodeARM64_x11 = 12, +RDI_RegCodeARM64_x12 = 13, +RDI_RegCodeARM64_x13 = 14, +RDI_RegCodeARM64_x14 = 15, +RDI_RegCodeARM64_x15 = 16, +RDI_RegCodeARM64_x16 = 17, +RDI_RegCodeARM64_x17 = 18, +RDI_RegCodeARM64_x18 = 19, +RDI_RegCodeARM64_x19 = 20, +RDI_RegCodeARM64_x20 = 21, +RDI_RegCodeARM64_x21 = 22, +RDI_RegCodeARM64_x22 = 23, +RDI_RegCodeARM64_x23 = 24, +RDI_RegCodeARM64_x24 = 25, +RDI_RegCodeARM64_x25 = 26, +RDI_RegCodeARM64_x26 = 27, +RDI_RegCodeARM64_x27 = 28, +RDI_RegCodeARM64_x28 = 29, +RDI_RegCodeARM64_x29 = 30, +RDI_RegCodeARM64_x30 = 31, +RDI_RegCodeARM64_x31 = 32, +RDI_RegCodeARM64_pc = 33, +RDI_RegCodeARM64_context_flags = 34, +RDI_RegCodeARM64_cpsr = 35, +RDI_RegCodeARM64_fpcr = 36, +RDI_RegCodeARM64_fpsr = 37, +RDI_RegCodeARM64_bcr0 = 38, +RDI_RegCodeARM64_bcr1 = 39, +RDI_RegCodeARM64_bcr2 = 40, +RDI_RegCodeARM64_bcr3 = 41, +RDI_RegCodeARM64_bcr4 = 42, +RDI_RegCodeARM64_bcr5 = 43, +RDI_RegCodeARM64_bcr6 = 44, +RDI_RegCodeARM64_bcr7 = 45, +RDI_RegCodeARM64_bvr0 = 46, +RDI_RegCodeARM64_bvr1 = 47, +RDI_RegCodeARM64_bvr2 = 48, +RDI_RegCodeARM64_bvr3 = 49, +RDI_RegCodeARM64_bvr4 = 50, +RDI_RegCodeARM64_bvr5 = 51, +RDI_RegCodeARM64_bvr6 = 52, +RDI_RegCodeARM64_bvr7 = 53, +RDI_RegCodeARM64_wcr0 = 54, +RDI_RegCodeARM64_wcr1 = 55, +RDI_RegCodeARM64_wvr0 = 56, +RDI_RegCodeARM64_wvr1 = 57, +RDI_RegCodeARM64_v0 = 58, +RDI_RegCodeARM64_v1 = 59, +RDI_RegCodeARM64_v2 = 60, +RDI_RegCodeARM64_v3 = 61, +RDI_RegCodeARM64_v4 = 62, +RDI_RegCodeARM64_v5 = 63, +RDI_RegCodeARM64_v6 = 64, +RDI_RegCodeARM64_v7 = 65, +RDI_RegCodeARM64_v8 = 66, +RDI_RegCodeARM64_v9 = 67, +RDI_RegCodeARM64_v10 = 68, +RDI_RegCodeARM64_v11 = 69, +RDI_RegCodeARM64_v12 = 70, +RDI_RegCodeARM64_v13 = 71, +RDI_RegCodeARM64_v14 = 72, +RDI_RegCodeARM64_v15 = 73, +RDI_RegCodeARM64_v16 = 74, +RDI_RegCodeARM64_v17 = 75, +RDI_RegCodeARM64_v18 = 76, +RDI_RegCodeARM64_v19 = 77, +RDI_RegCodeARM64_v20 = 78, +RDI_RegCodeARM64_v21 = 79, +RDI_RegCodeARM64_v22 = 80, +RDI_RegCodeARM64_v23 = 81, +RDI_RegCodeARM64_v24 = 82, +RDI_RegCodeARM64_v25 = 83, +RDI_RegCodeARM64_v26 = 84, +RDI_RegCodeARM64_v27 = 85, +RDI_RegCodeARM64_v28 = 86, +RDI_RegCodeARM64_v29 = 87, +RDI_RegCodeARM64_v30 = 88, +RDI_RegCodeARM64_v31 = 89, +} RDI_RegCodeARM64Enum; + typedef RDI_U32 RDI_BinarySectionFlags; typedef enum RDI_BinarySectionFlagsEnum { @@ -588,6 +684,7 @@ X(RDI_U64, idx)\ X(NULL)\ X(X86)\ X(X64)\ +X(ARM64)\ #define RDI_RegCodeX86_XList \ X(nil, 0)\ @@ -755,6 +852,98 @@ X(fip, 98)\ X(fdp, 99)\ X(mxcsr_mask, 100)\ +#define RDI_RegCodeARM64_XList \ +X(nil, 0)\ +X(x0, 1)\ +X(x1, 2)\ +X(x2, 3)\ +X(x3, 4)\ +X(x4, 5)\ +X(x5, 6)\ +X(x6, 7)\ +X(x7, 8)\ +X(x8, 9)\ +X(x9, 10)\ +X(x10, 11)\ +X(x11, 12)\ +X(x12, 13)\ +X(x13, 14)\ +X(x14, 15)\ +X(x15, 16)\ +X(x16, 17)\ +X(x17, 18)\ +X(x18, 19)\ +X(x19, 20)\ +X(x20, 21)\ +X(x21, 22)\ +X(x22, 23)\ +X(x23, 24)\ +X(x24, 25)\ +X(x25, 26)\ +X(x26, 27)\ +X(x27, 28)\ +X(x28, 29)\ +X(x29, 30)\ +X(x30, 31)\ +X(x31, 32)\ +X(pc, 33)\ +X(context_flags, 34)\ +X(cpsr, 35)\ +X(fpcr, 36)\ +X(fpsr, 37)\ +X(bcr0, 38)\ +X(bcr1, 39)\ +X(bcr2, 40)\ +X(bcr3, 41)\ +X(bcr4, 42)\ +X(bcr5, 43)\ +X(bcr6, 44)\ +X(bcr7, 45)\ +X(bvr0, 46)\ +X(bvr1, 47)\ +X(bvr2, 48)\ +X(bvr3, 49)\ +X(bvr4, 50)\ +X(bvr5, 51)\ +X(bvr6, 52)\ +X(bvr7, 53)\ +X(wcr0, 54)\ +X(wcr1, 55)\ +X(wvr0, 56)\ +X(wvr1, 57)\ +X(v0, 58)\ +X(v1, 59)\ +X(v2, 60)\ +X(v3, 61)\ +X(v4, 62)\ +X(v5, 63)\ +X(v6, 64)\ +X(v7, 65)\ +X(v8, 66)\ +X(v9, 67)\ +X(v10, 68)\ +X(v11, 69)\ +X(v12, 70)\ +X(v13, 71)\ +X(v14, 72)\ +X(v15, 73)\ +X(v16, 74)\ +X(v17, 75)\ +X(v18, 76)\ +X(v19, 77)\ +X(v20, 78)\ +X(v21, 79)\ +X(v22, 80)\ +X(v23, 81)\ +X(v24, 82)\ +X(v25, 83)\ +X(v26, 84)\ +X(v27, 85)\ +X(v28, 86)\ +X(v29, 87)\ +X(v30, 88)\ +X(v31, 89)\ + #define RDI_TopLevelInfo_XList \ X(RDI_Arch, arch)\ X(RDI_U32, exe_name_string_idx)\ diff --git a/src/metagen/metagen_base/metagen_base_context_cracking.h b/src/metagen/metagen_base/metagen_base_context_cracking.h index 040c00047..0f932b9a8 100644 --- a/src/metagen/metagen_base/metagen_base_context_cracking.h +++ b/src/metagen/metagen_base/metagen_base_context_cracking.h @@ -72,6 +72,7 @@ # define ARCH_X86 1 # elif defined(_M_ARM64) # define ARCH_ARM64 1 +# define USE_SOFT_INTRINSICS # elif defined(_M_ARM) # define ARCH_ARM32 1 # else @@ -110,7 +111,7 @@ //////////////////////////////// //~ rjf: Arch Cracking -#if defined(ARCH_X64) +#if defined(ARCH_X64) || defined(ARCH_ARM64) # define ARCH_64BIT 1 #elif defined(ARCH_X86) # define ARCH_32BIT 1 @@ -240,7 +241,7 @@ #if ARCH_X86 # error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported. #endif -#if !ARCH_X64 +#if !defined(ARCH_X64) && !defined(ARCH_ARM64) # error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported. #endif diff --git a/src/metagen/metagen_base/metagen_base_core.h b/src/metagen/metagen_base/metagen_base_core.h index b24838702..f8537d827 100644 --- a/src/metagen/metagen_base/metagen_base_core.h +++ b/src/metagen/metagen_base/metagen_base_core.h @@ -172,10 +172,12 @@ #if OS_WINDOWS # include -# include -# include # include # if ARCH_X64 +# include +# include +# endif +# if ARCH_X64 || ARCH_ARM64 # define ins_atomic_u64_eval(x) InterlockedAdd64((volatile __int64 *)(x), 0) # define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x)) # define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x)) diff --git a/src/metagen/metagen_base/metagen_base_strings.h b/src/metagen/metagen_base/metagen_base_strings.h index c68bdff69..4cbe2f2af 100644 --- a/src/metagen/metagen_base/metagen_base_strings.h +++ b/src/metagen/metagen_base/metagen_base_strings.h @@ -8,6 +8,9 @@ //~ rjf: Third Party Includes #define STB_SPRINTF_DECORATE(name) raddbg_##name +#ifdef ARCH_64BIT +#define stbsp__uintptr U64 +#endif #include "third_party/stb/stb_sprintf.h" //////////////////////////////// diff --git a/src/pe/pe.c b/src/pe/pe.c index 630ce5f71..8b6541c6e 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -5,22 +5,22 @@ //~ rjf: Basic Enum Functions internal U32 -pe_slot_count_from_unwind_op_code(PE_UnwindOpCode opcode) +pe_slot_count_from_unwind_op_code__x64(PE_UnwindOpCodeX64 opcode) { U32 result = 0; switch(opcode) { - case PE_UnwindOpCode_PUSH_NONVOL: result = 1; break; - case PE_UnwindOpCode_ALLOC_LARGE: result = 2; break; - case PE_UnwindOpCode_ALLOC_SMALL: result = 1; break; - case PE_UnwindOpCode_SET_FPREG: result = 1; break; - case PE_UnwindOpCode_SAVE_NONVOL: result = 2; break; - case PE_UnwindOpCode_SAVE_NONVOL_FAR: result = 3; break; - case PE_UnwindOpCode_EPILOG: result = 2; break; - case PE_UnwindOpCode_SPARE_CODE: result = 3; break; - case PE_UnwindOpCode_SAVE_XMM128: result = 2; break; - case PE_UnwindOpCode_SAVE_XMM128_FAR: result = 3; break; - case PE_UnwindOpCode_PUSH_MACHFRAME: result = 1; break; + case PE_UnwindOpCodeX64_PUSH_NONVOL: result = 1; break; + case PE_UnwindOpCodeX64_ALLOC_LARGE: result = 2; break; + case PE_UnwindOpCodeX64_ALLOC_SMALL: result = 1; break; + case PE_UnwindOpCodeX64_SET_FPREG: result = 1; break; + case PE_UnwindOpCodeX64_SAVE_NONVOL: result = 2; break; + case PE_UnwindOpCodeX64_SAVE_NONVOL_FAR: result = 3; break; + case PE_UnwindOpCodeX64_EPILOG: result = 2; break; + case PE_UnwindOpCodeX64_SPARE_CODE: result = 3; break; + case PE_UnwindOpCodeX64_SAVE_XMM128: result = 2; break; + case PE_UnwindOpCodeX64_SAVE_XMM128_FAR: result = 3; break; + case PE_UnwindOpCodeX64_PUSH_MACHFRAME: result = 1; break; } return result; } @@ -593,6 +593,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; tls_header.characteristics = (U64)tls_header32.characteristics; }break; + case COFF_MachineType_ARM64: case COFF_MachineType_X64: { str8_deserial_read_struct(data, tls_header_frng.min, &tls_header); @@ -1387,6 +1388,7 @@ pe_tls_from_data(Arena *arena, callback_addrs[i] = (U64)src[i]; } } break; + case COFF_MachineType_ARM64: case COFF_MachineType_X64: { str8_deserial_read_struct(raw_tls, 0, &header64); diff --git a/src/pe/pe.h b/src/pe/pe.h index 5df0890b3..7645b5adb 100644 --- a/src/pe/pe.h +++ b/src/pe/pe.h @@ -8,7 +8,7 @@ //~ rjf: PE Format-Defined Types/Constants #pragma pack(push,1) - + typedef struct PE_DosHeader PE_DosHeader; struct PE_DosHeader { @@ -481,6 +481,38 @@ struct PE_LoadConfig64 U64 cast_guard_os_determined_failure_mode; }; +typedef struct PE_ARM64ECMetadata PE_ARM64ECMetadata; +struct PE_ARM64ECMetadata +{ + U32 version; + U32 code_map; + U32 code_map_count; + U32 code_ranges_to_entry_point; + U32 redirection_metadata; + U32 os_arm64x_dispatch_call_no_redirect; + U32 os_arm64x_dispatch_ret; + U32 os_arm64x_dispatch_call; + U32 os_arm64x_dispatch_icall; + U32 os_arm64x_dispatch_icall_cfg; + U32 alternate_entry_point; + U32 auxiliary_iat; + U32 code_ranges_to_entry_points_count; + U32 redirection_metadata_count; + U32 get_x64_information_fptr; + U32 set_x64_information_fptr; + U32 extra_rfe_table; + U32 extra_rfe_table_size; + U32 os_arm64x_dispatch_fptr; + U32 auxilary_iat_copy; +}; + +typedef struct PE_ARM64ECCodeMapEntry PE_ARM64ECCodeMapEntry; +struct PE_ARM64ECCodeMapEntry +{ + U32 addr_start_and_arch; // least significant 2 bits are arch + U32 size; +}; + // this is the "MZ" as a 16-bit short #define PE_DOS_MAGIC 0x5a4d #define PE_MAGIC 0x00004550u @@ -518,6 +550,13 @@ struct PE_IntelPdata U32 voff_unwind_info; }; +typedef struct PE_Arm64Pdata PE_Arm64Pdata; +struct PE_Arm64Pdata +{ + U32 voff_first; + U32 combined; +}; + #define PE_CODEVIEW_PDB20_MAGIC 0x3031424e #define PE_CODEVIEW_PDB70_MAGIC 0x53445352 #define PE_CODEVIEW_RDI_MAGIC '0IDR' @@ -704,20 +743,20 @@ enum #define PE_BaseRelocKindFromEntry(x) (((x) >> 12) & 0xf) #define PE_BaseRelocMake(k, off) ((((U16)(k) & 0xf) << 12) | (U16)((off) & 0x1fff)) -typedef U32 PE_UnwindOpCode; +typedef U32 PE_UnwindOpCodeX64; enum { - PE_UnwindOpCode_PUSH_NONVOL = 0, - PE_UnwindOpCode_ALLOC_LARGE = 1, - PE_UnwindOpCode_ALLOC_SMALL = 2, - PE_UnwindOpCode_SET_FPREG = 3, - PE_UnwindOpCode_SAVE_NONVOL = 4, - PE_UnwindOpCode_SAVE_NONVOL_FAR = 5, - PE_UnwindOpCode_EPILOG = 6, - PE_UnwindOpCode_SPARE_CODE = 7, - PE_UnwindOpCode_SAVE_XMM128 = 8, - PE_UnwindOpCode_SAVE_XMM128_FAR = 9, - PE_UnwindOpCode_PUSH_MACHFRAME = 10, + PE_UnwindOpCodeX64_PUSH_NONVOL = 0, + PE_UnwindOpCodeX64_ALLOC_LARGE = 1, + PE_UnwindOpCodeX64_ALLOC_SMALL = 2, + PE_UnwindOpCodeX64_SET_FPREG = 3, + PE_UnwindOpCodeX64_SAVE_NONVOL = 4, + PE_UnwindOpCodeX64_SAVE_NONVOL_FAR = 5, + PE_UnwindOpCodeX64_EPILOG = 6, + PE_UnwindOpCodeX64_SPARE_CODE = 7, + PE_UnwindOpCodeX64_SAVE_XMM128 = 8, + PE_UnwindOpCodeX64_SAVE_XMM128_FAR = 9, + PE_UnwindOpCodeX64_PUSH_MACHFRAME = 10, }; typedef U8 PE_UnwindGprRegX64; @@ -741,20 +780,20 @@ enum PE_UnwindGprRegX64_R15 = 15, }; -typedef U8 PE_UnwindInfoFlags; +typedef U8 PE_UnwindInfoX64Flags; enum { - PE_UnwindInfoFlag_EHANDLER = (1<<0), - PE_UnwindInfoFlag_UHANDLER = (1<<1), - PE_UnwindInfoFlag_FHANDLER = 3, - PE_UnwindInfoFlag_CHAINED = (1<<2), + PE_UnwindInfoX64Flag_EHANDLER = (1<<0), + PE_UnwindInfoX64Flag_UHANDLER = (1<<1), + PE_UnwindInfoX64Flag_FHANDLER = 3, + PE_UnwindInfoX64Flag_CHAINED = (1<<2), }; #define PE_UNWIND_OPCODE_FROM_FLAGS(f) ((f)&0xF) #define PE_UNWIND_INFO_FROM_FLAGS(f) (((f) >> 4)&0xF) -typedef union PE_UnwindCode PE_UnwindCode; -union PE_UnwindCode +typedef union PE_UnwindCodeX64 PE_UnwindCodeX64; +union PE_UnwindCodeX64 { struct { @@ -770,8 +809,8 @@ union PE_UnwindCode #define PE_UNWIND_INFO_OFF_FROM_FRAME(x) (((x) >> 4)&0xF) #define PE_UNWIND_INFO_GET_CODE_COUNT(x) (((x)+1) & ~1) -typedef struct PE_UnwindInfo PE_UnwindInfo; -struct PE_UnwindInfo +typedef struct PE_UnwindInfoX64 PE_UnwindInfoX64; +struct PE_UnwindInfoX64 { U8 header; U8 prolog_size; @@ -779,6 +818,41 @@ struct PE_UnwindInfo U8 frame; }; +typedef U32 PE_UnwindOpCodeArm64; +enum +{ + PE_UnwindOpCodeArm64_none, // 0x00 + PE_UnwindOpCodeArm64_alloc_s, // 0x01 + PE_UnwindOpCodeArm64_alloc_m, // 0x02 + PE_UnwindOpCodeArm64_alloc_l, // 0x03 + PE_UnwindOpCodeArm64_save_fplr, // 0x04 + PE_UnwindOpCodeArm64_save_regp, // 0x05 + PE_UnwindOpCodeArm64_save_reg, // 0x06 + PE_UnwindOpCodeArm64_save_lrpair, // 0x07 + PE_UnwindOpCodeArm64_save_fregp, // 0x08 + PE_UnwindOpCodeArm64_save_freg, // 0x09 + PE_UnwindOpCodeArm64_save_qregp, // 0x0a + PE_UnwindOpCodeArm64_save_r19r20_x, // 0x0b + PE_UnwindOpCodeArm64_save_fplr_x, // 0x0c + PE_UnwindOpCodeArm64_save_regp_x, // 0x0d + PE_UnwindOpCodeArm64_save_reg_x, // 0x0e + PE_UnwindOpCodeArm64_save_fregp_x, // 0x0f + PE_UnwindOpCodeArm64_save_freg_x, // 0x10 + PE_UnwindOpCodeArm64_save_qregp_x, // 0x11 + PE_UnwindOpCodeArm64_set_fp, // 0x12 + PE_UnwindOpCodeArm64_add_fp, // 0x13 + PE_UnwindOpCodeArm64_nop, // 0x14 + PE_UnwindOpCodeArm64_end, // 0x15 + PE_UnwindOpCodeArm64_end_c, // 0x16 + PE_UnwindOpCodeArm64_save_next, // 0x17 + PE_UnwindOpCodeArm64_MSFT_OP_TRAP_FRAME, // 0x18 + PE_UnwindOpCodeArm64_MSFT_OP_MACHINE_FRAME, // 0x19 + PE_UnwindOpCodeArm64_MSFT_OP_CONTEXT, // 0x1a + PE_UnwindOpCodeArm64_MSFT_OP_EC_CONTEXT, // 0x1b + PE_UnwindOpCodeArm64_MSFT_OP_CLEAR_UNWOUND_TO_CALL, // 0x1c + PE_UnwindOpCodeArm64_pac_sign_lr, // 0x1d +}; + #pragma pack(pop) //////////////////////////////// @@ -797,6 +871,14 @@ read_only global String8 pe_dos_program = {pe_dos_program_data, sizeof(pe_dos_pr //////////////////////////////// //~ rjf: Parsed Info Types +//- antoniom: ARM64EC code ranges +typedef struct PE_HybridCodeRange PE_HybridCodeRange; +struct PE_HybridCodeRange +{ + Rng1U64 range; + Arch arch; +}; + //- rjf: relocation blocks typedef struct PE_BaseRelocBlock PE_BaseRelocBlock; @@ -1017,7 +1099,7 @@ struct PE_BinInfo //////////////////////////////// //~ rjf: Basic Enum Functions -internal U32 pe_slot_count_from_unwind_op_code(PE_UnwindOpCode opcode); +internal U32 pe_slot_count_from_unwind_op_code(PE_UnwindOpCodeX64 opcode); internal PE_WindowsSubsystem pe_subsystem_from_string(String8 string); internal String8 pe_string_from_subsystem(PE_WindowsSubsystem x); @@ -1047,6 +1129,7 @@ internal PE_ParsedTLS pe_tls_from_data(Arena *arena, COFF_MachineT //~ rjf: Helpers internal U64 pe_pdata_off_from_voff__binary_search_x8664(String8 raw_data, U64 voff); +internal U64 pe_pdata_off_from_voff__binary_search_arm64(String8 raw_data, PE_BinInfo *bin, U64 voff); internal void * pe_ptr_from_voff(String8 data, PE_BinInfo *bin, U64 voff); internal U64 pe_section_num_from_voff(String8 data, PE_BinInfo *bin, U64 voff); internal void * pe_ptr_from_section_num(String8 data, PE_BinInfo *bin, U64 n); diff --git a/src/rdi_format/rdi_format.mdesk b/src/rdi_format/rdi_format.mdesk index 2a5158987..97c9f773a 100644 --- a/src/rdi_format/rdi_format.mdesk +++ b/src/rdi_format/rdi_format.mdesk @@ -263,6 +263,7 @@ RDI_ArchTable: {NULL 0 0} {X86 1 4} {X64 2 8} + {ARM64 3 8} } @table(name value) @@ -437,6 +438,101 @@ RDI_RegCodeX64Table: {mxcsr_mask 100} } +@table(name value) +RDI_RegCodeARM64Table: +{ + {nil 0} + {x0 1} + {x1 2} + {x2 3} + {x3 4} + {x4 5} + {x5 6} + {x6 7} + {x7 8} + {x8 9} + {x9 10} + {x10 11} + {x11 12} + {x12 13} + {x13 14} + {x14 15} + {x15 16} + {x16 17} + {x17 18} + {x18 19} + {x19 20} + {x20 21} + {x21 22} + {x22 23} + {x23 24} + {x24 25} + {x25 26} + {x26 27} + {x27 28} + {x28 29} + {x29 30} + {x30 31} + {x31 32} + {pc 33} + {context_flags 34} + {cpsr 35} + {fpcr 36} + {fpsr 37} + {bcr0 38} + {bcr1 39} + {bcr2 40} + {bcr3 41} + {bcr4 42} + {bcr5 43} + {bcr6 44} + {bcr7 45} + {bvr0 46} + {bvr1 47} + {bvr2 48} + {bvr3 49} + {bvr4 50} + {bvr5 51} + {bvr6 52} + {bvr7 53} + {wcr0 54} + {wcr1 55} + {wvr0 56} + {wvr1 57} + {v0 58} + {v1 59} + {v2 60} + {v3 61} + {v4 62} + {v5 63} + {v6 64} + {v7 65} + {v8 66} + {v9 67} + {v10 68} + {v11 69} + {v12 70} + {v13 71} + {v14 72} + {v15 73} + {v16 74} + {v17 75} + {v18 76} + {v19 77} + {v20 78} + {v21 79} + {v22 80} + {v23 81} + {v24 82} + {v25 83} + {v26 84} + {v27 85} + {v28 86} + {v29 87} + {v30 88} + {v31 89} +} + @enum(RDI_U32) RDI_Arch: { @expand(RDI_ArchTable a) `$(a.name .. =>10) = $(a.value)` @@ -459,6 +555,11 @@ RDI_RegCodeX64Table: @expand(RDI_RegCodeX64Table a) `$(a.name .. =>10) = $(a.value)` } +@enum(RDI_U8) RDI_RegCodeARM64: +{ + @expand(RDI_RegCodeARM64Table a) `$(a.name .. =>10) = $(a.value)` +} + @xlist RDI_RegCodeX86_XList: { @expand(RDI_RegCodeX86Table a) `$(a.name), $(a.value)` @@ -469,6 +570,11 @@ RDI_RegCodeX64Table: @expand(RDI_RegCodeX64Table a) `$(a.name), $(a.value)` } +@xlist RDI_RegCodeARM64_XList: +{ + @expand(RDI_RegCodeARM64Table a) `$(a.name), $(a.value)` +} + //////////////////////////////// //~ rjf: Top-Level Info Type Tables diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index d1e19ae1b..d26d1c07e 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -185,8 +185,9 @@ p2r_rdi_arch_from_cv_arch(CV_Arch cv_arch) RDI_Arch result = 0; switch(cv_arch) { - case CV_Arch_8086: result = RDI_Arch_X86; break; - case CV_Arch_X64: result = RDI_Arch_X64; break; + case CV_Arch_8086: result = RDI_Arch_X86; break; + case CV_Arch_X64: result = RDI_Arch_X64; break; + case CV_Arch_ARM64: result = RDI_Arch_ARM64; break; //case CV_Arch_8080: break; //case CV_Arch_80286: break; //case CV_Arch_80386: break; @@ -243,7 +244,6 @@ p2r_rdi_arch_from_cv_arch(CV_Arch cv_arch) //case CV_Arch_EBC: break; //case CV_Arch_THUMB: break; //case CV_Arch_ARMNT: break; - //case CV_Arch_ARM64: break; //case CV_Arch_D3D11_SHADER: break; } return(result); @@ -270,6 +270,15 @@ p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code) { #define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegCodeX64_##RDN; break; CV_Reg_X64_XList(X) +#undef X + } + }break; + case RDI_Arch_ARM64: + { + switch(reg_code) + { +#define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegCodeARM64_##RDN; break; + CV_Reg_ARM64_XList(X) #undef X } }break; @@ -458,6 +467,23 @@ p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encod }break; } }break; + case RDI_Arch_ARM64: + { + switch(encoded_reg) + { + case CV_EncodedFramePtrReg_StackPtr: + { + result = RDI_RegCodeARM64_x31; + }break; + case CV_EncodedFramePtrReg_FramePtr: + { + result = RDI_RegCodeARM64_x29; + }break; + case CV_EncodedFramePtrReg_BasePtr: + { + }break; + } + }break; } return(result); } @@ -2556,6 +2582,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) default:{}break; case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; + case RDI_Arch_ARM64:{is_stack_reg = (cv_reg == CV_Regarm64_SP);}break; } if(is_stack_reg) { @@ -2601,6 +2628,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); }break; case RDI_Arch_X64: + case RDI_Arch_ARM64: { extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); }break; diff --git a/src/regs/generated/regs.meta.c b/src/regs/generated/regs.meta.c index c7f9f5388..c77860d33 100644 --- a/src/regs/generated/regs.meta.c +++ b/src/regs/generated/regs.meta.c @@ -11,6 +11,7 @@ switch(arch) default:{}break; case Arch_x64:{result = sizeof(REGS_RegBlockX64);}break; case Arch_x86:{result = sizeof(REGS_RegBlockX86);}break; +case Arch_arm64:{result = sizeof(REGS_RegBlockARM64);}break; } return result; } @@ -22,6 +23,7 @@ switch(arch) default:{}break; case Arch_x64:{result = REGS_RegCodeX64_COUNT;}break; case Arch_x86:{result = REGS_RegCodeX86_COUNT;}break; +case Arch_arm64:{result = REGS_RegCodeARM64_COUNT;}break; } return result; } @@ -33,6 +35,7 @@ switch(arch) default:{}break; case Arch_x64:{result = REGS_AliasCodeX64_COUNT;}break; case Arch_x86:{result = REGS_AliasCodeX86_COUNT;}break; +case Arch_arm64:{result = REGS_AliasCodeARM64_COUNT;}break; } return result; } @@ -44,6 +47,7 @@ switch(arch) default:{}break; case Arch_x64:{result = regs_g_reg_code_x64_string_table;}break; case Arch_x86:{result = regs_g_reg_code_x86_string_table;}break; +case Arch_arm64:{result = regs_g_reg_code_arm64_string_table;}break; } return result; } @@ -55,6 +59,7 @@ switch(arch) default:{}break; case Arch_x64:{result = regs_g_alias_code_x64_string_table;}break; case Arch_x86:{result = regs_g_alias_code_x86_string_table;}break; +case Arch_arm64:{result = regs_g_alias_code_arm64_string_table;}break; } return result; } @@ -66,6 +71,7 @@ switch(arch) default:{}break; case Arch_x64:{result = regs_g_reg_code_x64_rng_table;}break; case Arch_x86:{result = regs_g_reg_code_x86_rng_table;}break; +case Arch_arm64:{result = regs_g_reg_code_arm64_rng_table;}break; } return result; } @@ -77,6 +83,7 @@ switch(arch) default:{}break; case Arch_x64:{result = regs_g_alias_code_x64_slice_table;}break; case Arch_x86:{result = regs_g_alias_code_x86_slice_table;}break; +case Arch_arm64:{result = regs_g_alias_code_arm64_slice_table;}break; } return result; } @@ -88,6 +95,7 @@ switch(arch) default:{}break; case Arch_x64:{result = regs_g_reg_code_x64_usage_kind_table;}break; case Arch_x86:{result = regs_g_reg_code_x86_usage_kind_table;}break; +case Arch_arm64:{result = regs_g_reg_code_arm64_usage_kind_table;}break; } return result; } @@ -99,6 +107,7 @@ switch(arch) default:{}break; case Arch_x64:{result = regs_g_alias_code_x64_usage_kind_table;}break; case Arch_x86:{result = regs_g_alias_code_x86_usage_kind_table;}break; +case Arch_arm64:{result = regs_g_alias_code_arm64_usage_kind_table;}break; } return result; } @@ -1033,5 +1042,419 @@ REGS_Slice regs_g_alias_code_x86_slice_table[36] = {REGS_RegCodeX86_fpr7, 0, 8}, }; +REGS_UsageKind regs_g_reg_code_arm64_usage_kind_table[90] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +REGS_UsageKind regs_g_alias_code_arm64_usage_kind_table[40] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +String8 regs_g_reg_code_arm64_string_table[90] = +{ +str8_lit_comp(""), +str8_lit_comp("x0"), +str8_lit_comp("x1"), +str8_lit_comp("x2"), +str8_lit_comp("x3"), +str8_lit_comp("x4"), +str8_lit_comp("x5"), +str8_lit_comp("x6"), +str8_lit_comp("x7"), +str8_lit_comp("x8"), +str8_lit_comp("x9"), +str8_lit_comp("x10"), +str8_lit_comp("x11"), +str8_lit_comp("x12"), +str8_lit_comp("x13"), +str8_lit_comp("x14"), +str8_lit_comp("x15"), +str8_lit_comp("x16"), +str8_lit_comp("x17"), +str8_lit_comp("x18"), +str8_lit_comp("x19"), +str8_lit_comp("x20"), +str8_lit_comp("x21"), +str8_lit_comp("x22"), +str8_lit_comp("x23"), +str8_lit_comp("x24"), +str8_lit_comp("x25"), +str8_lit_comp("x26"), +str8_lit_comp("x27"), +str8_lit_comp("x28"), +str8_lit_comp("x29"), +str8_lit_comp("x30"), +str8_lit_comp("x31"), +str8_lit_comp("pc"), +str8_lit_comp("context_flags"), +str8_lit_comp("cpsr"), +str8_lit_comp("fpcr"), +str8_lit_comp("fpsr"), +str8_lit_comp("bcr0"), +str8_lit_comp("bcr1"), +str8_lit_comp("bcr2"), +str8_lit_comp("bcr3"), +str8_lit_comp("bcr4"), +str8_lit_comp("bcr5"), +str8_lit_comp("bcr6"), +str8_lit_comp("bcr7"), +str8_lit_comp("bvr0"), +str8_lit_comp("bvr1"), +str8_lit_comp("bvr2"), +str8_lit_comp("bvr3"), +str8_lit_comp("bvr4"), +str8_lit_comp("bvr5"), +str8_lit_comp("bvr6"), +str8_lit_comp("bvr7"), +str8_lit_comp("wcr0"), +str8_lit_comp("wcr1"), +str8_lit_comp("wvr0"), +str8_lit_comp("wvr1"), +str8_lit_comp("v0"), +str8_lit_comp("v1"), +str8_lit_comp("v2"), +str8_lit_comp("v3"), +str8_lit_comp("v4"), +str8_lit_comp("v5"), +str8_lit_comp("v6"), +str8_lit_comp("v7"), +str8_lit_comp("v8"), +str8_lit_comp("v9"), +str8_lit_comp("v10"), +str8_lit_comp("v11"), +str8_lit_comp("v12"), +str8_lit_comp("v13"), +str8_lit_comp("v14"), +str8_lit_comp("v15"), +str8_lit_comp("v16"), +str8_lit_comp("v17"), +str8_lit_comp("v18"), +str8_lit_comp("v19"), +str8_lit_comp("v20"), +str8_lit_comp("v21"), +str8_lit_comp("v22"), +str8_lit_comp("v23"), +str8_lit_comp("v24"), +str8_lit_comp("v25"), +str8_lit_comp("v26"), +str8_lit_comp("v27"), +str8_lit_comp("v28"), +str8_lit_comp("v29"), +str8_lit_comp("v30"), +str8_lit_comp("v31"), +}; + +String8 regs_g_alias_code_arm64_string_table[40] = +{ +str8_lit_comp(""), +str8_lit_comp("xip0"), +str8_lit_comp("xip1"), +str8_lit_comp("xpr"), +str8_lit_comp("fp"), +str8_lit_comp("lr"), +str8_lit_comp("zr"), +str8_lit_comp("sp"), +str8_lit_comp("w0"), +str8_lit_comp("w1"), +str8_lit_comp("w2"), +str8_lit_comp("w3"), +str8_lit_comp("w4"), +str8_lit_comp("w5"), +str8_lit_comp("w6"), +str8_lit_comp("w7"), +str8_lit_comp("w8"), +str8_lit_comp("w9"), +str8_lit_comp("w10"), +str8_lit_comp("w11"), +str8_lit_comp("w12"), +str8_lit_comp("w13"), +str8_lit_comp("w14"), +str8_lit_comp("w15"), +str8_lit_comp("w16"), +str8_lit_comp("w17"), +str8_lit_comp("w18"), +str8_lit_comp("w19"), +str8_lit_comp("w20"), +str8_lit_comp("w21"), +str8_lit_comp("w22"), +str8_lit_comp("w23"), +str8_lit_comp("w24"), +str8_lit_comp("w25"), +str8_lit_comp("w26"), +str8_lit_comp("w27"), +str8_lit_comp("w28"), +str8_lit_comp("w29"), +str8_lit_comp("w30"), +str8_lit_comp("w31"), +}; + +REGS_Rng regs_g_reg_code_arm64_rng_table[90] = +{ +{0}, +{(U16)OffsetOf(REGS_RegBlockARM64, x0), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x1), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x2), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x3), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x4), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x5), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x6), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x7), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x8), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x9), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x10), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x11), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x12), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x13), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x14), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x15), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x16), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x17), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x18), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x19), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x20), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x21), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x22), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x23), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x24), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x25), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x26), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x27), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x28), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x29), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x30), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, x31), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, pc), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, context_flags), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, cpsr), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, fpcr), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, fpsr), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr0), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr1), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr2), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr3), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr4), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr5), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr6), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bcr7), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr0), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr1), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr2), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr3), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr4), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr5), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr6), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, bvr7), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, wcr0), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, wcr1), 4}, +{(U16)OffsetOf(REGS_RegBlockARM64, wvr0), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, wvr1), 8}, +{(U16)OffsetOf(REGS_RegBlockARM64, v0), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v1), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v2), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v3), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v4), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v5), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v6), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v7), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v8), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v9), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v10), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v11), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v12), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v13), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v14), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v15), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v16), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v17), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v18), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v19), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v20), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v21), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v22), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v23), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v24), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v25), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v26), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v27), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v28), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v29), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v30), 16}, +{(U16)OffsetOf(REGS_RegBlockARM64, v31), 16}, +}; + +REGS_Slice regs_g_alias_code_arm64_slice_table[40] = +{ +{0}, +{REGS_RegCodeARM64_x16, 0, 8}, +{REGS_RegCodeARM64_x17, 0, 8}, +{REGS_RegCodeARM64_x18, 0, 8}, +{REGS_RegCodeARM64_x29, 0, 8}, +{REGS_RegCodeARM64_x30, 0, 8}, +{REGS_RegCodeARM64_x31, 0, 8}, +{REGS_RegCodeARM64_x31, 0, 8}, +{REGS_RegCodeARM64_x0, 0, 4}, +{REGS_RegCodeARM64_x1, 0, 4}, +{REGS_RegCodeARM64_x2, 0, 4}, +{REGS_RegCodeARM64_x3, 0, 4}, +{REGS_RegCodeARM64_x4, 0, 4}, +{REGS_RegCodeARM64_x5, 0, 4}, +{REGS_RegCodeARM64_x6, 0, 4}, +{REGS_RegCodeARM64_x7, 0, 4}, +{REGS_RegCodeARM64_x8, 0, 4}, +{REGS_RegCodeARM64_x9, 0, 4}, +{REGS_RegCodeARM64_x10, 0, 4}, +{REGS_RegCodeARM64_x11, 0, 4}, +{REGS_RegCodeARM64_x12, 0, 4}, +{REGS_RegCodeARM64_x13, 0, 4}, +{REGS_RegCodeARM64_x14, 0, 4}, +{REGS_RegCodeARM64_x15, 0, 4}, +{REGS_RegCodeARM64_x16, 0, 4}, +{REGS_RegCodeARM64_x17, 0, 4}, +{REGS_RegCodeARM64_x18, 0, 4}, +{REGS_RegCodeARM64_x19, 0, 4}, +{REGS_RegCodeARM64_x20, 0, 4}, +{REGS_RegCodeARM64_x21, 0, 4}, +{REGS_RegCodeARM64_x22, 0, 4}, +{REGS_RegCodeARM64_x23, 0, 4}, +{REGS_RegCodeARM64_x24, 0, 4}, +{REGS_RegCodeARM64_x25, 0, 4}, +{REGS_RegCodeARM64_x26, 0, 4}, +{REGS_RegCodeARM64_x27, 0, 4}, +{REGS_RegCodeARM64_x28, 0, 4}, +{REGS_RegCodeARM64_x29, 0, 4}, +{REGS_RegCodeARM64_x30, 0, 4}, +{REGS_RegCodeARM64_x31, 0, 4}, +}; + C_LINKAGE_END diff --git a/src/regs/generated/regs.meta.h b/src/regs/generated/regs.meta.h index c2abaac98..2f702f1f8 100644 --- a/src/regs/generated/regs.meta.h +++ b/src/regs/generated/regs.meta.h @@ -320,6 +320,146 @@ REGS_AliasCodeX86_mm7, REGS_AliasCodeX86_COUNT, } REGS_AliasCodeX86; +typedef enum REGS_RegCodeARM64 +{ +REGS_RegCodeARM64_NULL, +REGS_RegCodeARM64_x0, +REGS_RegCodeARM64_x1, +REGS_RegCodeARM64_x2, +REGS_RegCodeARM64_x3, +REGS_RegCodeARM64_x4, +REGS_RegCodeARM64_x5, +REGS_RegCodeARM64_x6, +REGS_RegCodeARM64_x7, +REGS_RegCodeARM64_x8, +REGS_RegCodeARM64_x9, +REGS_RegCodeARM64_x10, +REGS_RegCodeARM64_x11, +REGS_RegCodeARM64_x12, +REGS_RegCodeARM64_x13, +REGS_RegCodeARM64_x14, +REGS_RegCodeARM64_x15, +REGS_RegCodeARM64_x16, +REGS_RegCodeARM64_x17, +REGS_RegCodeARM64_x18, +REGS_RegCodeARM64_x19, +REGS_RegCodeARM64_x20, +REGS_RegCodeARM64_x21, +REGS_RegCodeARM64_x22, +REGS_RegCodeARM64_x23, +REGS_RegCodeARM64_x24, +REGS_RegCodeARM64_x25, +REGS_RegCodeARM64_x26, +REGS_RegCodeARM64_x27, +REGS_RegCodeARM64_x28, +REGS_RegCodeARM64_x29, +REGS_RegCodeARM64_x30, +REGS_RegCodeARM64_x31, +REGS_RegCodeARM64_pc, +REGS_RegCodeARM64_context_flags, +REGS_RegCodeARM64_cpsr, +REGS_RegCodeARM64_fpcr, +REGS_RegCodeARM64_fpsr, +REGS_RegCodeARM64_bcr0, +REGS_RegCodeARM64_bcr1, +REGS_RegCodeARM64_bcr2, +REGS_RegCodeARM64_bcr3, +REGS_RegCodeARM64_bcr4, +REGS_RegCodeARM64_bcr5, +REGS_RegCodeARM64_bcr6, +REGS_RegCodeARM64_bcr7, +REGS_RegCodeARM64_bvr0, +REGS_RegCodeARM64_bvr1, +REGS_RegCodeARM64_bvr2, +REGS_RegCodeARM64_bvr3, +REGS_RegCodeARM64_bvr4, +REGS_RegCodeARM64_bvr5, +REGS_RegCodeARM64_bvr6, +REGS_RegCodeARM64_bvr7, +REGS_RegCodeARM64_wcr0, +REGS_RegCodeARM64_wcr1, +REGS_RegCodeARM64_wvr0, +REGS_RegCodeARM64_wvr1, +REGS_RegCodeARM64_v0, +REGS_RegCodeARM64_v1, +REGS_RegCodeARM64_v2, +REGS_RegCodeARM64_v3, +REGS_RegCodeARM64_v4, +REGS_RegCodeARM64_v5, +REGS_RegCodeARM64_v6, +REGS_RegCodeARM64_v7, +REGS_RegCodeARM64_v8, +REGS_RegCodeARM64_v9, +REGS_RegCodeARM64_v10, +REGS_RegCodeARM64_v11, +REGS_RegCodeARM64_v12, +REGS_RegCodeARM64_v13, +REGS_RegCodeARM64_v14, +REGS_RegCodeARM64_v15, +REGS_RegCodeARM64_v16, +REGS_RegCodeARM64_v17, +REGS_RegCodeARM64_v18, +REGS_RegCodeARM64_v19, +REGS_RegCodeARM64_v20, +REGS_RegCodeARM64_v21, +REGS_RegCodeARM64_v22, +REGS_RegCodeARM64_v23, +REGS_RegCodeARM64_v24, +REGS_RegCodeARM64_v25, +REGS_RegCodeARM64_v26, +REGS_RegCodeARM64_v27, +REGS_RegCodeARM64_v28, +REGS_RegCodeARM64_v29, +REGS_RegCodeARM64_v30, +REGS_RegCodeARM64_v31, +REGS_RegCodeARM64_COUNT, +} REGS_RegCodeARM64; + +typedef enum REGS_AliasCodeARM64 +{ +REGS_AliasCodeARM64_NULL, +REGS_AliasCodeARM64_xip0, +REGS_AliasCodeARM64_xip1, +REGS_AliasCodeARM64_xpr, +REGS_AliasCodeARM64_fp, +REGS_AliasCodeARM64_lr, +REGS_AliasCodeARM64_zr, +REGS_AliasCodeARM64_sp, +REGS_AliasCodeARM64_w0, +REGS_AliasCodeARM64_w1, +REGS_AliasCodeARM64_w2, +REGS_AliasCodeARM64_w3, +REGS_AliasCodeARM64_w4, +REGS_AliasCodeARM64_w5, +REGS_AliasCodeARM64_w6, +REGS_AliasCodeARM64_w7, +REGS_AliasCodeARM64_w8, +REGS_AliasCodeARM64_w9, +REGS_AliasCodeARM64_w10, +REGS_AliasCodeARM64_w11, +REGS_AliasCodeARM64_w12, +REGS_AliasCodeARM64_w13, +REGS_AliasCodeARM64_w14, +REGS_AliasCodeARM64_w15, +REGS_AliasCodeARM64_w16, +REGS_AliasCodeARM64_w17, +REGS_AliasCodeARM64_w18, +REGS_AliasCodeARM64_w19, +REGS_AliasCodeARM64_w20, +REGS_AliasCodeARM64_w21, +REGS_AliasCodeARM64_w22, +REGS_AliasCodeARM64_w23, +REGS_AliasCodeARM64_w24, +REGS_AliasCodeARM64_w25, +REGS_AliasCodeARM64_w26, +REGS_AliasCodeARM64_w27, +REGS_AliasCodeARM64_w28, +REGS_AliasCodeARM64_w29, +REGS_AliasCodeARM64_w30, +REGS_AliasCodeARM64_w31, +REGS_AliasCodeARM64_COUNT, +} REGS_AliasCodeARM64; + typedef struct REGS_RegBlockX64 REGS_RegBlockX64; struct REGS_RegBlockX64 { @@ -490,6 +630,100 @@ REGS_Reg256 ymm6; REGS_Reg256 ymm7; }; +typedef struct REGS_RegBlockARM64 REGS_RegBlockARM64; +struct REGS_RegBlockARM64 +{ +REGS_Reg64 x0; +REGS_Reg64 x1; +REGS_Reg64 x2; +REGS_Reg64 x3; +REGS_Reg64 x4; +REGS_Reg64 x5; +REGS_Reg64 x6; +REGS_Reg64 x7; +REGS_Reg64 x8; +REGS_Reg64 x9; +REGS_Reg64 x10; +REGS_Reg64 x11; +REGS_Reg64 x12; +REGS_Reg64 x13; +REGS_Reg64 x14; +REGS_Reg64 x15; +REGS_Reg64 x16; +REGS_Reg64 x17; +REGS_Reg64 x18; +REGS_Reg64 x19; +REGS_Reg64 x20; +REGS_Reg64 x21; +REGS_Reg64 x22; +REGS_Reg64 x23; +REGS_Reg64 x24; +REGS_Reg64 x25; +REGS_Reg64 x26; +REGS_Reg64 x27; +REGS_Reg64 x28; +REGS_Reg64 x29; +REGS_Reg64 x30; +REGS_Reg64 x31; +REGS_Reg64 pc; +REGS_Reg32 context_flags; +REGS_Reg32 cpsr; +REGS_Reg32 fpcr; +REGS_Reg32 fpsr; +REGS_Reg32 bcr0; +REGS_Reg32 bcr1; +REGS_Reg32 bcr2; +REGS_Reg32 bcr3; +REGS_Reg32 bcr4; +REGS_Reg32 bcr5; +REGS_Reg32 bcr6; +REGS_Reg32 bcr7; +REGS_Reg64 bvr0; +REGS_Reg64 bvr1; +REGS_Reg64 bvr2; +REGS_Reg64 bvr3; +REGS_Reg64 bvr4; +REGS_Reg64 bvr5; +REGS_Reg64 bvr6; +REGS_Reg64 bvr7; +REGS_Reg32 wcr0; +REGS_Reg32 wcr1; +REGS_Reg64 wvr0; +REGS_Reg64 wvr1; +REGS_Reg128 v0; +REGS_Reg128 v1; +REGS_Reg128 v2; +REGS_Reg128 v3; +REGS_Reg128 v4; +REGS_Reg128 v5; +REGS_Reg128 v6; +REGS_Reg128 v7; +REGS_Reg128 v8; +REGS_Reg128 v9; +REGS_Reg128 v10; +REGS_Reg128 v11; +REGS_Reg128 v12; +REGS_Reg128 v13; +REGS_Reg128 v14; +REGS_Reg128 v15; +REGS_Reg128 v16; +REGS_Reg128 v17; +REGS_Reg128 v18; +REGS_Reg128 v19; +REGS_Reg128 v20; +REGS_Reg128 v21; +REGS_Reg128 v22; +REGS_Reg128 v23; +REGS_Reg128 v24; +REGS_Reg128 v25; +REGS_Reg128 v26; +REGS_Reg128 v27; +REGS_Reg128 v28; +REGS_Reg128 v29; +REGS_Reg128 v30; +REGS_Reg128 v31; +}; + C_LINKAGE_BEGIN extern REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[101]; extern REGS_UsageKind regs_g_alias_code_x64_usage_kind_table[96]; @@ -503,6 +737,12 @@ extern String8 regs_g_reg_code_x86_string_table[61]; extern String8 regs_g_alias_code_x86_string_table[36]; extern REGS_Rng regs_g_reg_code_x86_rng_table[61]; extern REGS_Slice regs_g_alias_code_x86_slice_table[36]; +extern REGS_UsageKind regs_g_reg_code_arm64_usage_kind_table[90]; +extern REGS_UsageKind regs_g_alias_code_arm64_usage_kind_table[40]; +extern String8 regs_g_reg_code_arm64_string_table[90]; +extern String8 regs_g_alias_code_arm64_string_table[40]; +extern REGS_Rng regs_g_reg_code_arm64_rng_table[90]; +extern REGS_Slice regs_g_alias_code_arm64_slice_table[40]; C_LINKAGE_END diff --git a/src/regs/rdi/generated/regs_rdi.meta.c b/src/regs/rdi/generated/regs_rdi.meta.c index 9b0cdf652..acb39dce3 100644 --- a/src/regs/rdi/generated/regs_rdi.meta.c +++ b/src/regs/rdi/generated/regs_rdi.meta.c @@ -116,6 +116,102 @@ case REGS_RegCodeX64_k6:{result = RDI_RegCodeX64_k6;}break; case REGS_RegCodeX64_k7:{result = RDI_RegCodeX64_k7;}break; } }break; +case Arch_arm64: +{ +switch(code) +{ +default:{}break; +case REGS_RegCodeARM64_x0:{result = RDI_RegCodeARM64_x0;}break; +case REGS_RegCodeARM64_x1:{result = RDI_RegCodeARM64_x1;}break; +case REGS_RegCodeARM64_x2:{result = RDI_RegCodeARM64_x2;}break; +case REGS_RegCodeARM64_x3:{result = RDI_RegCodeARM64_x3;}break; +case REGS_RegCodeARM64_x4:{result = RDI_RegCodeARM64_x4;}break; +case REGS_RegCodeARM64_x5:{result = RDI_RegCodeARM64_x5;}break; +case REGS_RegCodeARM64_x6:{result = RDI_RegCodeARM64_x6;}break; +case REGS_RegCodeARM64_x7:{result = RDI_RegCodeARM64_x7;}break; +case REGS_RegCodeARM64_x8:{result = RDI_RegCodeARM64_x8;}break; +case REGS_RegCodeARM64_x9:{result = RDI_RegCodeARM64_x9;}break; +case REGS_RegCodeARM64_x10:{result = RDI_RegCodeARM64_x10;}break; +case REGS_RegCodeARM64_x11:{result = RDI_RegCodeARM64_x11;}break; +case REGS_RegCodeARM64_x12:{result = RDI_RegCodeARM64_x12;}break; +case REGS_RegCodeARM64_x13:{result = RDI_RegCodeARM64_x13;}break; +case REGS_RegCodeARM64_x14:{result = RDI_RegCodeARM64_x14;}break; +case REGS_RegCodeARM64_x15:{result = RDI_RegCodeARM64_x15;}break; +case REGS_RegCodeARM64_x16:{result = RDI_RegCodeARM64_x16;}break; +case REGS_RegCodeARM64_x17:{result = RDI_RegCodeARM64_x17;}break; +case REGS_RegCodeARM64_x18:{result = RDI_RegCodeARM64_x18;}break; +case REGS_RegCodeARM64_x19:{result = RDI_RegCodeARM64_x19;}break; +case REGS_RegCodeARM64_x20:{result = RDI_RegCodeARM64_x20;}break; +case REGS_RegCodeARM64_x21:{result = RDI_RegCodeARM64_x21;}break; +case REGS_RegCodeARM64_x22:{result = RDI_RegCodeARM64_x22;}break; +case REGS_RegCodeARM64_x23:{result = RDI_RegCodeARM64_x23;}break; +case REGS_RegCodeARM64_x24:{result = RDI_RegCodeARM64_x24;}break; +case REGS_RegCodeARM64_x25:{result = RDI_RegCodeARM64_x25;}break; +case REGS_RegCodeARM64_x26:{result = RDI_RegCodeARM64_x26;}break; +case REGS_RegCodeARM64_x27:{result = RDI_RegCodeARM64_x27;}break; +case REGS_RegCodeARM64_x28:{result = RDI_RegCodeARM64_x28;}break; +case REGS_RegCodeARM64_x29:{result = RDI_RegCodeARM64_x29;}break; +case REGS_RegCodeARM64_x30:{result = RDI_RegCodeARM64_x30;}break; +case REGS_RegCodeARM64_x31:{result = RDI_RegCodeARM64_x31;}break; +case REGS_RegCodeARM64_pc:{result = RDI_RegCodeARM64_pc;}break; +case REGS_RegCodeARM64_context_flags:{result = RDI_RegCodeARM64_context_flags;}break; +case REGS_RegCodeARM64_cpsr:{result = RDI_RegCodeARM64_cpsr;}break; +case REGS_RegCodeARM64_fpcr:{result = RDI_RegCodeARM64_fpcr;}break; +case REGS_RegCodeARM64_fpsr:{result = RDI_RegCodeARM64_fpsr;}break; +case REGS_RegCodeARM64_bcr0:{result = RDI_RegCodeARM64_bcr0;}break; +case REGS_RegCodeARM64_bcr1:{result = RDI_RegCodeARM64_bcr1;}break; +case REGS_RegCodeARM64_bcr2:{result = RDI_RegCodeARM64_bcr2;}break; +case REGS_RegCodeARM64_bcr3:{result = RDI_RegCodeARM64_bcr3;}break; +case REGS_RegCodeARM64_bcr4:{result = RDI_RegCodeARM64_bcr4;}break; +case REGS_RegCodeARM64_bcr5:{result = RDI_RegCodeARM64_bcr5;}break; +case REGS_RegCodeARM64_bcr6:{result = RDI_RegCodeARM64_bcr6;}break; +case REGS_RegCodeARM64_bcr7:{result = RDI_RegCodeARM64_bcr7;}break; +case REGS_RegCodeARM64_bvr0:{result = RDI_RegCodeARM64_bvr0;}break; +case REGS_RegCodeARM64_bvr1:{result = RDI_RegCodeARM64_bvr1;}break; +case REGS_RegCodeARM64_bvr2:{result = RDI_RegCodeARM64_bvr2;}break; +case REGS_RegCodeARM64_bvr3:{result = RDI_RegCodeARM64_bvr3;}break; +case REGS_RegCodeARM64_bvr4:{result = RDI_RegCodeARM64_bvr4;}break; +case REGS_RegCodeARM64_bvr5:{result = RDI_RegCodeARM64_bvr5;}break; +case REGS_RegCodeARM64_bvr6:{result = RDI_RegCodeARM64_bvr6;}break; +case REGS_RegCodeARM64_bvr7:{result = RDI_RegCodeARM64_bvr7;}break; +case REGS_RegCodeARM64_wcr0:{result = RDI_RegCodeARM64_wcr0;}break; +case REGS_RegCodeARM64_wcr1:{result = RDI_RegCodeARM64_wcr1;}break; +case REGS_RegCodeARM64_wvr0:{result = RDI_RegCodeARM64_wvr0;}break; +case REGS_RegCodeARM64_wvr1:{result = RDI_RegCodeARM64_wvr1;}break; +case REGS_RegCodeARM64_v0:{result = RDI_RegCodeARM64_v0;}break; +case REGS_RegCodeARM64_v1:{result = RDI_RegCodeARM64_v1;}break; +case REGS_RegCodeARM64_v2:{result = RDI_RegCodeARM64_v2;}break; +case REGS_RegCodeARM64_v3:{result = RDI_RegCodeARM64_v3;}break; +case REGS_RegCodeARM64_v4:{result = RDI_RegCodeARM64_v4;}break; +case REGS_RegCodeARM64_v5:{result = RDI_RegCodeARM64_v5;}break; +case REGS_RegCodeARM64_v6:{result = RDI_RegCodeARM64_v6;}break; +case REGS_RegCodeARM64_v7:{result = RDI_RegCodeARM64_v7;}break; +case REGS_RegCodeARM64_v8:{result = RDI_RegCodeARM64_v8;}break; +case REGS_RegCodeARM64_v9:{result = RDI_RegCodeARM64_v9;}break; +case REGS_RegCodeARM64_v10:{result = RDI_RegCodeARM64_v10;}break; +case REGS_RegCodeARM64_v11:{result = RDI_RegCodeARM64_v11;}break; +case REGS_RegCodeARM64_v12:{result = RDI_RegCodeARM64_v12;}break; +case REGS_RegCodeARM64_v13:{result = RDI_RegCodeARM64_v13;}break; +case REGS_RegCodeARM64_v14:{result = RDI_RegCodeARM64_v14;}break; +case REGS_RegCodeARM64_v15:{result = RDI_RegCodeARM64_v15;}break; +case REGS_RegCodeARM64_v16:{result = RDI_RegCodeARM64_v16;}break; +case REGS_RegCodeARM64_v17:{result = RDI_RegCodeARM64_v17;}break; +case REGS_RegCodeARM64_v18:{result = RDI_RegCodeARM64_v18;}break; +case REGS_RegCodeARM64_v19:{result = RDI_RegCodeARM64_v19;}break; +case REGS_RegCodeARM64_v20:{result = RDI_RegCodeARM64_v20;}break; +case REGS_RegCodeARM64_v21:{result = RDI_RegCodeARM64_v21;}break; +case REGS_RegCodeARM64_v22:{result = RDI_RegCodeARM64_v22;}break; +case REGS_RegCodeARM64_v23:{result = RDI_RegCodeARM64_v23;}break; +case REGS_RegCodeARM64_v24:{result = RDI_RegCodeARM64_v24;}break; +case REGS_RegCodeARM64_v25:{result = RDI_RegCodeARM64_v25;}break; +case REGS_RegCodeARM64_v26:{result = RDI_RegCodeARM64_v26;}break; +case REGS_RegCodeARM64_v27:{result = RDI_RegCodeARM64_v27;}break; +case REGS_RegCodeARM64_v28:{result = RDI_RegCodeARM64_v28;}break; +case REGS_RegCodeARM64_v29:{result = RDI_RegCodeARM64_v29;}break; +case REGS_RegCodeARM64_v30:{result = RDI_RegCodeARM64_v30;}break; +case REGS_RegCodeARM64_v31:{result = RDI_RegCodeARM64_v31;}break; +} +}break; case Arch_x86: { switch(code) @@ -299,6 +395,102 @@ case RDI_RegCodeX64_k6:{result = REGS_RegCodeX64_k6;}break; case RDI_RegCodeX64_k7:{result = REGS_RegCodeX64_k7;}break; } }break; +case Arch_arm64: +{ +switch(code) +{ +default:{}break; +case RDI_RegCodeARM64_x0:{result = REGS_RegCodeARM64_x0;}break; +case RDI_RegCodeARM64_x1:{result = REGS_RegCodeARM64_x1;}break; +case RDI_RegCodeARM64_x2:{result = REGS_RegCodeARM64_x2;}break; +case RDI_RegCodeARM64_x3:{result = REGS_RegCodeARM64_x3;}break; +case RDI_RegCodeARM64_x4:{result = REGS_RegCodeARM64_x4;}break; +case RDI_RegCodeARM64_x5:{result = REGS_RegCodeARM64_x5;}break; +case RDI_RegCodeARM64_x6:{result = REGS_RegCodeARM64_x6;}break; +case RDI_RegCodeARM64_x7:{result = REGS_RegCodeARM64_x7;}break; +case RDI_RegCodeARM64_x8:{result = REGS_RegCodeARM64_x8;}break; +case RDI_RegCodeARM64_x9:{result = REGS_RegCodeARM64_x9;}break; +case RDI_RegCodeARM64_x10:{result = REGS_RegCodeARM64_x10;}break; +case RDI_RegCodeARM64_x11:{result = REGS_RegCodeARM64_x11;}break; +case RDI_RegCodeARM64_x12:{result = REGS_RegCodeARM64_x12;}break; +case RDI_RegCodeARM64_x13:{result = REGS_RegCodeARM64_x13;}break; +case RDI_RegCodeARM64_x14:{result = REGS_RegCodeARM64_x14;}break; +case RDI_RegCodeARM64_x15:{result = REGS_RegCodeARM64_x15;}break; +case RDI_RegCodeARM64_x16:{result = REGS_RegCodeARM64_x16;}break; +case RDI_RegCodeARM64_x17:{result = REGS_RegCodeARM64_x17;}break; +case RDI_RegCodeARM64_x18:{result = REGS_RegCodeARM64_x18;}break; +case RDI_RegCodeARM64_x19:{result = REGS_RegCodeARM64_x19;}break; +case RDI_RegCodeARM64_x20:{result = REGS_RegCodeARM64_x20;}break; +case RDI_RegCodeARM64_x21:{result = REGS_RegCodeARM64_x21;}break; +case RDI_RegCodeARM64_x22:{result = REGS_RegCodeARM64_x22;}break; +case RDI_RegCodeARM64_x23:{result = REGS_RegCodeARM64_x23;}break; +case RDI_RegCodeARM64_x24:{result = REGS_RegCodeARM64_x24;}break; +case RDI_RegCodeARM64_x25:{result = REGS_RegCodeARM64_x25;}break; +case RDI_RegCodeARM64_x26:{result = REGS_RegCodeARM64_x26;}break; +case RDI_RegCodeARM64_x27:{result = REGS_RegCodeARM64_x27;}break; +case RDI_RegCodeARM64_x28:{result = REGS_RegCodeARM64_x28;}break; +case RDI_RegCodeARM64_x29:{result = REGS_RegCodeARM64_x29;}break; +case RDI_RegCodeARM64_x30:{result = REGS_RegCodeARM64_x30;}break; +case RDI_RegCodeARM64_x31:{result = REGS_RegCodeARM64_x31;}break; +case RDI_RegCodeARM64_pc:{result = REGS_RegCodeARM64_pc;}break; +case RDI_RegCodeARM64_context_flags:{result = REGS_RegCodeARM64_context_flags;}break; +case RDI_RegCodeARM64_cpsr:{result = REGS_RegCodeARM64_cpsr;}break; +case RDI_RegCodeARM64_fpcr:{result = REGS_RegCodeARM64_fpcr;}break; +case RDI_RegCodeARM64_fpsr:{result = REGS_RegCodeARM64_fpsr;}break; +case RDI_RegCodeARM64_bcr0:{result = REGS_RegCodeARM64_bcr0;}break; +case RDI_RegCodeARM64_bcr1:{result = REGS_RegCodeARM64_bcr1;}break; +case RDI_RegCodeARM64_bcr2:{result = REGS_RegCodeARM64_bcr2;}break; +case RDI_RegCodeARM64_bcr3:{result = REGS_RegCodeARM64_bcr3;}break; +case RDI_RegCodeARM64_bcr4:{result = REGS_RegCodeARM64_bcr4;}break; +case RDI_RegCodeARM64_bcr5:{result = REGS_RegCodeARM64_bcr5;}break; +case RDI_RegCodeARM64_bcr6:{result = REGS_RegCodeARM64_bcr6;}break; +case RDI_RegCodeARM64_bcr7:{result = REGS_RegCodeARM64_bcr7;}break; +case RDI_RegCodeARM64_bvr0:{result = REGS_RegCodeARM64_bvr0;}break; +case RDI_RegCodeARM64_bvr1:{result = REGS_RegCodeARM64_bvr1;}break; +case RDI_RegCodeARM64_bvr2:{result = REGS_RegCodeARM64_bvr2;}break; +case RDI_RegCodeARM64_bvr3:{result = REGS_RegCodeARM64_bvr3;}break; +case RDI_RegCodeARM64_bvr4:{result = REGS_RegCodeARM64_bvr4;}break; +case RDI_RegCodeARM64_bvr5:{result = REGS_RegCodeARM64_bvr5;}break; +case RDI_RegCodeARM64_bvr6:{result = REGS_RegCodeARM64_bvr6;}break; +case RDI_RegCodeARM64_bvr7:{result = REGS_RegCodeARM64_bvr7;}break; +case RDI_RegCodeARM64_wcr0:{result = REGS_RegCodeARM64_wcr0;}break; +case RDI_RegCodeARM64_wcr1:{result = REGS_RegCodeARM64_wcr1;}break; +case RDI_RegCodeARM64_wvr0:{result = REGS_RegCodeARM64_wvr0;}break; +case RDI_RegCodeARM64_wvr1:{result = REGS_RegCodeARM64_wvr1;}break; +case RDI_RegCodeARM64_v0:{result = REGS_RegCodeARM64_v0;}break; +case RDI_RegCodeARM64_v1:{result = REGS_RegCodeARM64_v1;}break; +case RDI_RegCodeARM64_v2:{result = REGS_RegCodeARM64_v2;}break; +case RDI_RegCodeARM64_v3:{result = REGS_RegCodeARM64_v3;}break; +case RDI_RegCodeARM64_v4:{result = REGS_RegCodeARM64_v4;}break; +case RDI_RegCodeARM64_v5:{result = REGS_RegCodeARM64_v5;}break; +case RDI_RegCodeARM64_v6:{result = REGS_RegCodeARM64_v6;}break; +case RDI_RegCodeARM64_v7:{result = REGS_RegCodeARM64_v7;}break; +case RDI_RegCodeARM64_v8:{result = REGS_RegCodeARM64_v8;}break; +case RDI_RegCodeARM64_v9:{result = REGS_RegCodeARM64_v9;}break; +case RDI_RegCodeARM64_v10:{result = REGS_RegCodeARM64_v10;}break; +case RDI_RegCodeARM64_v11:{result = REGS_RegCodeARM64_v11;}break; +case RDI_RegCodeARM64_v12:{result = REGS_RegCodeARM64_v12;}break; +case RDI_RegCodeARM64_v13:{result = REGS_RegCodeARM64_v13;}break; +case RDI_RegCodeARM64_v14:{result = REGS_RegCodeARM64_v14;}break; +case RDI_RegCodeARM64_v15:{result = REGS_RegCodeARM64_v15;}break; +case RDI_RegCodeARM64_v16:{result = REGS_RegCodeARM64_v16;}break; +case RDI_RegCodeARM64_v17:{result = REGS_RegCodeARM64_v17;}break; +case RDI_RegCodeARM64_v18:{result = REGS_RegCodeARM64_v18;}break; +case RDI_RegCodeARM64_v19:{result = REGS_RegCodeARM64_v19;}break; +case RDI_RegCodeARM64_v20:{result = REGS_RegCodeARM64_v20;}break; +case RDI_RegCodeARM64_v21:{result = REGS_RegCodeARM64_v21;}break; +case RDI_RegCodeARM64_v22:{result = REGS_RegCodeARM64_v22;}break; +case RDI_RegCodeARM64_v23:{result = REGS_RegCodeARM64_v23;}break; +case RDI_RegCodeARM64_v24:{result = REGS_RegCodeARM64_v24;}break; +case RDI_RegCodeARM64_v25:{result = REGS_RegCodeARM64_v25;}break; +case RDI_RegCodeARM64_v26:{result = REGS_RegCodeARM64_v26;}break; +case RDI_RegCodeARM64_v27:{result = REGS_RegCodeARM64_v27;}break; +case RDI_RegCodeARM64_v28:{result = REGS_RegCodeARM64_v28;}break; +case RDI_RegCodeARM64_v29:{result = REGS_RegCodeARM64_v29;}break; +case RDI_RegCodeARM64_v30:{result = REGS_RegCodeARM64_v30;}break; +case RDI_RegCodeARM64_v31:{result = REGS_RegCodeARM64_v31;}break; +} +}break; case Arch_x86: { switch(code) diff --git a/src/regs/rdi/regs_rdi.mdesk b/src/regs/rdi/regs_rdi.mdesk index e3961b840..dd7f1295e 100644 --- a/src/regs/rdi/regs_rdi.mdesk +++ b/src/regs/rdi/regs_rdi.mdesk @@ -28,6 +28,14 @@ @expand(REGS_RegTableX86 a) `case REGS_RegCodeX86_$(a.name):{result = RDI_RegCodeX86_$(a.name);}break;`; `}`; `}break;`; + `case Arch_arm64:`; + `{`; + `switch(code)` + `{`; + `default:{}break;`; + @expand(REGS_RegTableARM64 a) `case REGS_RegCodeARM64_$(a.name):{result = RDI_RegCodeARM64_$(a.name);}break;`; + `}`; + `}break;`; `}`; `return result;`; `}`; @@ -57,6 +65,14 @@ @expand(REGS_RegTableX86 a) `case RDI_RegCodeX86_$(a.name):{result = REGS_RegCodeX86_$(a.name);}break;`; `}`; `}break;`; + `case Arch_arm64:`; + `{`; + `switch(code)` + `{`; + `default:{}break;`; + @expand(REGS_RegTableARM64 a) `case RDI_RegCodeARM64_$(a.name):{result = REGS_RegCodeARM64_$(a.name);}break;`; + `}`; + `}break;`; `}`; `return result;`; `}`; diff --git a/src/regs/regs.c b/src/regs/regs.c index 1cd17c356..8640c89c1 100644 --- a/src/regs/regs.c +++ b/src/regs/regs.c @@ -18,6 +18,7 @@ regs_rip_from_arch_block(Arch arch, void *block) default:{}break; case Arch_x64:{result = ((REGS_RegBlockX64 *)block)->rip.u64;}break; case Arch_x86:{result = (U64)((REGS_RegBlockX86 *)block)->eip.u32;}break; + case Arch_arm64:{result = ((REGS_RegBlockARM64 *)block)->pc.u64;}break; } return result; } @@ -31,6 +32,7 @@ regs_rsp_from_arch_block(Arch arch, void *block) default:{}break; case Arch_x64:{result = ((REGS_RegBlockX64 *)block)->rsp.u64;}break; case Arch_x86:{result = (U64)((REGS_RegBlockX86 *)block)->esp.u32;}break; + case Arch_arm64:{result = ((REGS_RegBlockARM64 *)block)->x31.u64;}break; } return result; } @@ -43,6 +45,7 @@ regs_arch_block_write_rip(Arch arch, void *block, U64 rip) default:{}break; case Arch_x64:{((REGS_RegBlockX64 *)block)->rip.u64 = rip;}break; case Arch_x86:{((REGS_RegBlockX86 *)block)->eip.u32 = (U32)rip;}break; + case Arch_arm64:{((REGS_RegBlockARM64 *)block)->pc.u64 = rip;}break; } } @@ -54,5 +57,6 @@ regs_arch_block_write_rsp(Arch arch, void *block, U64 rsp) default:{}break; case Arch_x64:{((REGS_RegBlockX64 *)block)->rsp.u64 = rsp;}break; case Arch_x86:{((REGS_RegBlockX86 *)block)->esp.u32 = (U32)rsp;}break; + case Arch_arm64:{((REGS_RegBlockARM64 *)block)->x31.u64 = rsp;}break; } } diff --git a/src/regs/regs.mdesk b/src/regs/regs.mdesk index 2f68c43e2..f748d0b63 100644 --- a/src/regs/regs.mdesk +++ b/src/regs/regs.mdesk @@ -326,6 +326,147 @@ REGS_AliasTableX86: {mm7 fpr7 0 64 Normal} } +//////////////////////////////// +//~ rjf: ARM64 Tables + +@table(name size usage) +REGS_RegTableARM64: +{ + {x0 64 Normal} + {x1 64 Normal} + {x2 64 Normal} + {x3 64 Normal} + {x4 64 Normal} + {x5 64 Normal} + {x6 64 Normal} + {x7 64 Normal} + {x8 64 Normal} + {x9 64 Normal} + {x10 64 Normal} + {x11 64 Normal} + {x12 64 Normal} + {x13 64 Normal} + {x14 64 Normal} + {x15 64 Normal} + {x16 64 Normal} + {x17 64 Normal} + {x18 64 Normal} + {x19 64 Normal} + {x20 64 Normal} + {x21 64 Normal} + {x22 64 Normal} + {x23 64 Normal} + {x24 64 Normal} + {x25 64 Normal} + {x26 64 Normal} + {x27 64 Normal} + {x28 64 Normal} + {x29 64 Normal} + {x30 64 Normal} + {x31 64 Normal} + {pc 64 Normal} + {context_flags 32 Normal} + {cpsr 32 Normal} + {fpcr 32 Normal} + {fpsr 32 Normal} + {bcr0 32 Normal} + {bcr1 32 Normal} + {bcr2 32 Normal} + {bcr3 32 Normal} + {bcr4 32 Normal} + {bcr5 32 Normal} + {bcr6 32 Normal} + {bcr7 32 Normal} + {bvr0 64 Normal} + {bvr1 64 Normal} + {bvr2 64 Normal} + {bvr3 64 Normal} + {bvr4 64 Normal} + {bvr5 64 Normal} + {bvr6 64 Normal} + {bvr7 64 Normal} + {wcr0 32 Normal} + {wcr1 32 Normal} + {wvr0 64 Normal} + {wvr1 64 Normal} + {v0 128 Normal} + {v1 128 Normal} + {v2 128 Normal} + {v3 128 Normal} + {v4 128 Normal} + {v5 128 Normal} + {v6 128 Normal} + {v7 128 Normal} + {v8 128 Normal} + {v9 128 Normal} + {v10 128 Normal} + {v11 128 Normal} + {v12 128 Normal} + {v13 128 Normal} + {v14 128 Normal} + {v15 128 Normal} + {v16 128 Normal} + {v17 128 Normal} + {v18 128 Normal} + {v19 128 Normal} + {v20 128 Normal} + {v21 128 Normal} + {v22 128 Normal} + {v23 128 Normal} + {v24 128 Normal} + {v25 128 Normal} + {v26 128 Normal} + {v27 128 Normal} + {v28 128 Normal} + {v29 128 Normal} + {v30 128 Normal} + {v31 128 Normal} +} + +@table(name base off size usage) +REGS_AliasTableARM64: +{ + {xip0 x16 0 64 Normal} + {xip1 x17 0 64 Normal} + {xpr x18 0 64 Normal} + {fp x29 0 64 Normal} + {lr x30 0 64 Normal} + {zr x31 0 64 Normal} + {sp x31 0 64 Normal} + {w0 x0 0 32 Normal} + {w1 x1 0 32 Normal} + {w2 x2 0 32 Normal} + {w3 x3 0 32 Normal} + {w4 x4 0 32 Normal} + {w5 x5 0 32 Normal} + {w6 x6 0 32 Normal} + {w7 x7 0 32 Normal} + {w8 x8 0 32 Normal} + {w9 x9 0 32 Normal} + {w10 x10 0 32 Normal} + {w11 x11 0 32 Normal} + {w12 x12 0 32 Normal} + {w13 x13 0 32 Normal} + {w14 x14 0 32 Normal} + {w15 x15 0 32 Normal} + {w16 x16 0 32 Normal} + {w17 x17 0 32 Normal} + {w18 x18 0 32 Normal} + {w19 x19 0 32 Normal} + {w20 x20 0 32 Normal} + {w21 x21 0 32 Normal} + {w22 x22 0 32 Normal} + {w23 x23 0 32 Normal} + {w24 x24 0 32 Normal} + {w25 x25 0 32 Normal} + {w26 x26 0 32 Normal} + {w27 x27 0 32 Normal} + {w28 x28 0 32 Normal} + {w29 x29 0 32 Normal} + {w30 x30 0 32 Normal} + {w31 x31 0 32 Normal} +} + //////////////////////////////// //~ rjf: Architecture Tables @@ -334,6 +475,7 @@ REGS_ArchTable: { {X64 x64} {X86 x86} + {ARM64 arm64} } //////////////////////////////// @@ -454,6 +596,65 @@ regs_g_reg_code_x86_usage_kind_table: @expand(REGS_AliasTableX86 a) `{REGS_RegCodeX86_$(a.base), $(a.off/8), $(a.size/8)}`, } +//////////////////////////////// +//~ antoniom: ARM64 Generators + +@enum REGS_RegCodeARM64: +{ + NULL, + @expand(REGS_RegTableARM64 a) `$(a.name)`, + COUNT, +} + +@enum REGS_AliasCodeARM64: +{ + NULL, + @expand(REGS_AliasTableARM64 a) `$(a.name)`, + COUNT, +} + +@struct REGS_RegBlockARM64: +{ + @expand(REGS_RegTableARM64 a) `REGS_Reg$(a.size) $(a.name)`, +} + +@data(REGS_UsageKind) regs_g_reg_code_arm64_usage_kind_table: +{ + `REGS_UsageKind_Normal`; + @expand(REGS_RegTableARM64 a) `REGS_UsageKind_$(a.usage)`; +} + +@data(REGS_UsageKind) +regs_g_alias_code_arm64_usage_kind_table: +{ + `REGS_UsageKind_Normal`; + @expand(REGS_AliasTableARM64 a) `REGS_UsageKind_$(a.usage)`; +} + +@data(String8) regs_g_reg_code_arm64_string_table: +{ + `str8_lit_comp("")`; + @expand(REGS_RegTableARM64 a) `str8_lit_comp("$(a.name)")`; +} + +@data(String8) regs_g_alias_code_arm64_string_table: +{ + `str8_lit_comp("")`; + @expand(REGS_AliasTableARM64 a) `str8_lit_comp("$(a.name)")`; +} + +@data(REGS_Rng) regs_g_reg_code_arm64_rng_table: +{ + `{0}`; + @expand(REGS_RegTableARM64 a) `{(U16)OffsetOf(REGS_RegBlockARM64, $(a.name)), $(a.size/8)}`, +} + +@data(REGS_Slice) regs_g_alias_code_arm64_slice_table: +{ + `{0}`; + @expand(REGS_AliasTableARM64 a) `{REGS_RegCodeARM64_$(a.base), $(a.off/8), $(a.size/8)}`, +} + //////////////////////////////// //~ rjf: Architecture-Dynamic Helper Implementation Generators diff --git a/src/third_party/armadillo/LICENSE b/src/third_party/armadillo/LICENSE new file mode 100644 index 000000000..c628a1482 --- /dev/null +++ b/src/third_party/armadillo/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2019, Justin Sherman +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. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. diff --git a/src/third_party/armadillo/source/BranchExcSys.c b/src/third_party/armadillo/source/BranchExcSys.c new file mode 100644 index 000000000..b0a7112bc --- /dev/null +++ b/src/third_party/armadillo/source/BranchExcSys.c @@ -0,0 +1,1560 @@ +#include +#include + +#include "adefs.h" +#include "bits.h" +#include "common.h" +#include "instruction.h" +#include "utils.h" +#include "strext.h" + +static S32 DisassembleConditionalImmediateBranchInstr(struct instruction *i, + struct ad_insn *out){ + U32 o1 = bits(i->opcode, 24, 24); + U32 imm19 = bits(i->opcode, 5, 23); + U32 o0 = bits(i->opcode, 4, 4); + U32 cond = bits(i->opcode, 0, 3); + + if(o1 != 0 && o0 != 0) + return 1; + + ADD_FIELD(out, o1); + ADD_FIELD(out, imm19); + ADD_FIELD(out, o0); + ADD_FIELD(out, cond); + + U64 imm = sign_extend(imm19 << 2, 64) + i->PC; + const char *dc = decode_cond(cond); + + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + concat(&DECODE_STR(out), "b.%s #%#lx", dc, imm); + + SET_INSTR_ID(out, AD_INSTR_B); + SET_CC(out, cond); + + return 0; +} + +static S32 DisassembleExcGenInstr(struct instruction *i, struct ad_insn *out){ + U32 opc = bits(i->opcode, 21, 23); + U32 imm16 = bits(i->opcode, 5, 20); + U32 op2 = bits(i->opcode, 2, 4); + U32 LL = bits(i->opcode, 0, 1); + + if(op2 != 0) + return 1; + + ADD_FIELD(out, opc); + ADD_FIELD(out, imm16); + ADD_FIELD(out, op2); + ADD_FIELD(out, LL); + + S32 instr_id = AD_NONE; + + if(opc == 0 && LL > 0){ + struct { + const char *instr_s; + S32 instr_id; + } tab[] = { + { NULL, AD_NONE }, + { "svc", AD_INSTR_SVC }, + { "hvc", AD_INSTR_HVC }, + { "smc", AD_INSTR_SMC } + }; + + instr_id = tab[LL].instr_id; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm16); + + concat(&DECODE_STR(out), "%s #%#x", tab[LL].instr_s, imm16); + } + else if((opc == 1 || opc == 2) && LL == 0){ + struct { + const char *instr_s; + S32 instr_id; + } tab[] = { + { NULL, AD_NONE }, + { "brk", AD_INSTR_BRK }, + { "hlt", AD_INSTR_HLT } + }; + + instr_id = tab[opc].instr_id; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm16); + + concat(&DECODE_STR(out), "%s #%#x", tab[opc].instr_s, imm16); + } + else if(opc == 5 && LL > 0){ + S32 tab[] = { AD_NONE, AD_INSTR_DCPS1, AD_INSTR_DCPS2, AD_INSTR_DCPS3 }; + instr_id = tab[LL]; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm16); + + concat(&DECODE_STR(out), "dcps%d #%#x", LL, imm16); + } + else{ + return 1; + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleHintInstr(struct instruction *i, struct ad_insn *out){ + U32 CRm = bits(i->opcode, 8, 11); + U32 op2 = bits(i->opcode, 5, 7); + + ADD_FIELD(out, CRm); + ADD_FIELD(out, op2); + + S32 instr_id = AD_NONE; + + struct itab first[] = { + { "nop", AD_INSTR_NOP }, + { "yield", AD_INSTR_YIELD }, + { "wfe", AD_INSTR_WFE }, + { "wfi", AD_INSTR_WFI }, + { "sev", AD_INSTR_SEV }, + { "sevl", AD_INSTR_SEVL }, + { NULL, AD_NONE }, + { "xpaclri", AD_INSTR_XPACLRI } + }; + + struct itab second[] = { + { "pacia1716", AD_INSTR_PACIA1716 }, + { NULL, AD_NONE }, + { "pacib1716", AD_INSTR_PACIB1716 }, + { NULL, AD_NONE }, + { "autia1716", AD_INSTR_AUTIA1716 }, + { NULL, AD_NONE }, + { "autib1716", AD_INSTR_AUTIB1716 } + }; + + struct itab third[] = { + { "esb", AD_INSTR_ESB }, + { "psb csync", AD_INSTR_PSB_CSYNC }, + { "tsb csync", AD_INSTR_TSB_CSYNC }, + { "csdb", AD_INSTR_CSDB } + }; + + struct itab fourth[] = { + { "paciaz", AD_INSTR_PACIAZ }, + { "paciasp", AD_INSTR_PACIASP }, + { "pacibz", AD_INSTR_PACIBZ }, + { "pacibsp", AD_INSTR_PACIBSP }, + { "autiaz", AD_INSTR_AUTIAZ }, + { "autiasp", AD_INSTR_AUTIASP }, + { "autibz", AD_INSTR_AUTIBZ }, + { "autibsp", AD_INSTR_AUTIBSP } + }; + + if(CRm == 4 && (op2 & ~6) == 0){ + instr_id = AD_INSTR_BTI; + + U32 indirection = op2 >> 1; + + const char *tbl[] = { "", " c", " j", " jc" }; + + concat(&DECODE_STR(out), "bti%s", tbl[indirection]); + } + else{ + struct itab *tab = NULL; + + if(CRm == 0){ + if(OOB(op2, first)) + return 1; + + tab = first; + } + else if(CRm == 1){ + if(OOB(op2, second)) + return 1; + + tab = second; + } + else if(CRm == 2){ + if(OOB(op2, third)) + return 1; + + tab = third; + } + else if(CRm == 3){ + if(OOB(op2, fourth)) + return 1; + + tab = fourth; + } + + if(!tab) + return 1; + + const char *instr_s = tab[op2].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[op2].instr_id; + + concat(&DECODE_STR(out), "%s", instr_s); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleBarrierInstr(struct instruction *i, + struct ad_insn *out){ + U32 CRm = bits(i->opcode, 8, 11); + U32 op2 = bits(i->opcode, 5, 7); + U32 Rt = bits(i->opcode, 0, 4); + + if(op2 == 0 || op2 == 1) + return 1; + + if(Rt != 0x1f) + return 1; + + ADD_FIELD(out, CRm); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + if(op2 == 4 || op2 == 5){ + const char *barrier_ops[] = { "#0x0", "oshld", "oshst", "osh", "#0x4", + "nshld", "nshst", "nsh", "#0x8", "ishld", "ishst", "ish", "#0xb", + "ld", "st", "sy" + }; + + const char *instr_s = NULL; + + if(op2 == 5){ + instr_s = "dmb"; + instr_id = AD_INSTR_DMB; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRm); + } + else if((CRm & ~4) != 0){ + instr_s = "dsb"; + instr_id = AD_INSTR_DSB; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRm); + } + else if(CRm == 0){ + instr_s = "ssbb"; + instr_id = AD_INSTR_SSBB; + } + else if(CRm == 4){ + instr_s = "pssbb"; + instr_id = AD_INSTR_PSSBB; + } + + if(!instr_s) + return 1; + + concat(&DECODE_STR(out), "%s", instr_s); + + if(instr_id == AD_INSTR_DSB || instr_id == AD_INSTR_DMB) + concat(&DECODE_STR(out), " %s", barrier_ops[CRm]); + } + else if(op2 == 2){ + instr_id = AD_INSTR_CLREX; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRm); + + concat(&DECODE_STR(out), "clrex"); + + if(CRm != 0) + concat(&DECODE_STR(out), " #%#x", CRm); + } + else if(op2 == 6){ + instr_id = AD_INSTR_ISB; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRm); + + concat(&DECODE_STR(out), "isb"); + + if(CRm == 0xf) + concat(&DECODE_STR(out), " sy"); + else + concat(&DECODE_STR(out), " #%#x", CRm); + } + else if(op2 == 0xf){ + instr_id = AD_INSTR_SB; + + concat(&DECODE_STR(out), "sb"); + } + else{ + return 1; + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassemblePSTATEInstr(struct instruction *i, struct ad_insn *out){ + U32 op1 = bits(i->opcode, 16, 18); + U32 CRm = bits(i->opcode, 8, 11); + U32 op2 = bits(i->opcode, 5, 7); + U32 Rt = bits(i->opcode, 0, 4); + + if(Rt != 0x1f) + return 1; + + ADD_FIELD(out, op1); + ADD_FIELD(out, CRm); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + if(op1 == 0 && (op2 == 0 || op2 == 1 || op2 == 2)){ + struct { + const char *instr_s; + S32 instr_id; + } tab[] = { + { "cfinv", AD_INSTR_CFINV }, + { "xaflag", AD_INSTR_XAFLAG }, + { "axflag", AD_INSTR_AXFLAG } + }; + + if(OOB(op2, tab)) + return 1; + + instr_id = tab[op2].instr_id; + + concat(&DECODE_STR(out), "%s", tab[op2].instr_s); + } + else{ + instr_id = AD_INSTR_MSR; + + U32 pstatefield = (op1 << 3) | op2; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&pstatefield); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRm); + + /* easier to split cases up like this rather than testing pstatefield */ + if(op1 == 0){ + const char *ptbl[] = { NULL, NULL, NULL, "UAO", "PAN", "SPSel" }; + + if(OOB(op2, ptbl)) + return 1; + + if(!ptbl[op2]) + return 1; + + concat(&DECODE_STR(out), "msr %s", ptbl[op2]); + } + else{ + const char *ptbl[] = { NULL, "SSBS", "DIT", NULL, "TCO", NULL, + "DAIFSet", "DAIFClr" + }; + + if(OOB(op2, ptbl)) + return 1; + + if(!ptbl[op2]) + return 1; + + concat(&DECODE_STR(out), "msr %s", ptbl[op2]); + } + + concat(&DECODE_STR(out), ", #%#x", CRm); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +enum { + Sys_AT = 0, Sys_DC, Sys_IC, Sys_TLBI, Sys_SYS +}; + +static S32 SysOp(U32 op1, U32 CRn, U32 CRm, U32 op2){ + U32 encoding = (op1 << 11); + encoding |= (CRn << 7); + encoding |= (CRm << 3); + encoding |= op2; + + switch(encoding){ + case 0x3c0: return Sys_AT; + case 0x23c0: return Sys_AT; + case 0x33c0: return Sys_AT; + case 0x3c1: return Sys_AT; + case 0x23c1: return Sys_AT; + case 0x33c1: return Sys_AT; + case 0x3c2: return Sys_AT; + case 0x3c3: return Sys_AT; + case 0x23c4: return Sys_AT; + case 0x23c5: return Sys_AT; + case 0x23c6: return Sys_AT; + case 0x23c7: return Sys_AT; + case 0x1ba1: return Sys_DC; + case 0x3b1: return Sys_DC; + case 0x3b2: return Sys_DC; + case 0x1bd1: return Sys_DC; + case 0x3d2: return Sys_DC; + case 0x1bd9: return Sys_DC; + case 0x1bf1: return Sys_DC; + case 0x3f2: return Sys_DC; + case 0x1be9: return Sys_DC; + case 0x388: return Sys_IC; + case 0x3a8: return Sys_IC; + case 0x1ba9: return Sys_IC; + case 0x2401: return Sys_TLBI; + case 0x2405: return Sys_TLBI; + case 0x418: return Sys_TLBI; + case 0x2418: return Sys_TLBI; + case 0x3418: return Sys_TLBI; + case 0x419: return Sys_TLBI; + case 0x2419: return Sys_TLBI; + case 0x3419: return Sys_TLBI; + case 0x41a: return Sys_TLBI; + case 0x41b: return Sys_TLBI; + case 0x241c: return Sys_TLBI; + case 0x41d: return Sys_TLBI; + case 0x241d: return Sys_TLBI; + case 0x341d: return Sys_TLBI; + case 0x241e: return Sys_TLBI; + case 0x41f: return Sys_TLBI; + case 0x2421: return Sys_TLBI; + case 0x2425: return Sys_TLBI; + case 0x438: return Sys_TLBI; + case 0x2438: return Sys_TLBI; + case 0x3438: return Sys_TLBI; + case 0x439: return Sys_TLBI; + case 0x2439: return Sys_TLBI; + case 0x3439: return Sys_TLBI; + case 0x43a: return Sys_TLBI; + case 0x43b: return Sys_TLBI; + case 0x243c: return Sys_TLBI; + case 0x43d: return Sys_TLBI; + case 0x243d: return Sys_TLBI; + case 0x343d: return Sys_TLBI; + case 0x243e: return Sys_TLBI; + case 0x43f: return Sys_TLBI; + default: return Sys_SYS; + }; +} + +static const char *at_op(U32 encoding){ + switch(encoding){ + case 0x0: return "S1E1R"; + case 0x1: return "S1E1W"; + case 0x2: return "S1E0R"; + case 0x3: return "S1E0W"; + case 0x40: return "S1E2R"; + case 0x41: return "S1E2W"; + case 0x44: return "S12E1R"; + case 0x45: return "S12E1W"; + case 0x46: return "S12E0R"; + case 0x47: return "S12E0W"; + case 0x60: return "S1E3R"; + case 0x61: return "S1E3W"; + case 0x8: return "S1E1RP"; + case 0x9: return "S1E1WP"; + default: return NULL; + }; +} + +static const char *dc_op(U32 encoding){ + switch(encoding){ + case 0x31: return "IVAC"; + case 0x32: return "ISW"; + case 0x52: return "CSW"; + case 0x72: return "CISW"; + case 0x1a1: return "ZVA"; + case 0x1d1: return "CVAC"; + case 0x1d9: return "CVAU"; + case 0x1f1: return "CIVAC"; + case 0x33: return "IGVAC"; + case 0x34: return "IGSW"; + case 0x35: return "IGDVAC"; + case 0x36: return "IGDSW"; + case 0x54: return "CGSW"; + case 0x56: return "CGDSW"; + case 0x74: return "CIGSW"; + case 0x76: return "CIGDSW"; + case 0x1a3: return "GVA"; + case 0x1a4: return "GZVA"; + case 0x1d3: return "CGVAC"; + case 0x1d5: return "CGDVAC"; + case 0x1e3: return "CGVAP"; + case 0x1e5: return "CGDVAP"; + case 0x1eb: return "CGVADP"; + case 0x1ed: return "CGDVADP"; + case 0x1f3: return "CIGVAC"; + case 0x1f5: return "CIGDVAC"; + case 0x1e1: return "CVAP"; + case 0x1e9: return "CVADP"; + default: return NULL; + }; +}; + +static const char *ic_op(U32 encoding){ + switch(encoding){ + case 0x8: return "IALLUIS"; + case 0x28: return "IALLU"; + case 0x1a9: return "IVAU"; + default: return NULL; + }; +} + +static const char *tlbi_op(U32 encoding){ + switch(encoding){ + case 0x18: return "VMALLE1IS"; + case 0x19: return "VAE1IS"; + case 0x1a: return "ASIDE1IS"; + case 0x1b: return "VAAE1IS"; + case 0x1d: return "VALE1IS"; + case 0x1f: return "VAALE1IS"; + case 0x38: return "VMALLE1"; + case 0x39: return "VAE1"; + case 0x3a: return "ASIDE1"; + case 0x3b: return "VAAE1"; + case 0x3d: return "VALE1"; + case 0x3f: return "VAALE1"; + case 0x201: return "IPAS2E1IS"; + case 0x205: return "IPAS2LE1IS"; + case 0x218: return "ALLE2IS"; + case 0x219: return "VAE2IS"; + case 0x21c: return "ALLE1IS"; + case 0x21d: return "VALE2IS"; + case 0x21e: return "VMALLS12E1IS"; + case 0x221: return "IPAS2E1"; + case 0x225: return "IPAS2LE1"; + case 0x238: return "ALLE2"; + case 0x239: return "VAE2"; + case 0x23c: return "ALLE1"; + case 0x23d: return "VALE2"; + case 0x23e: return "VMALLS12E1"; + case 0x318: return "ALLE3IS"; + case 0x319: return "VAE3IS"; + case 0x31d: return "VALE3IS"; + case 0x338: return "ALLE3"; + case 0x339: return "VAE3"; + case 0x33d: return "VALE3"; + case 0x8: return "VMALLE1OS"; + case 0x9: return "VAE1OS"; + case 0xa: return "ASIDE1OS"; + case 0xb: return "VAAE1OS"; + case 0xd: return "VALE1OS"; + case 0xf: return "VAALE1OS"; + case 0x11: return "RVAE1IS"; + case 0x13: return "RVAAE1IS"; + case 0x15: return "RVALE1IS"; + case 0x17: return "RVAALE1IS"; + case 0x29: return "RVAE1OS"; + case 0x2b: return "RVAAE1OS"; + case 0x2d: return "RVALE1OS"; + case 0x2f: return "RVAALE1OS"; + case 0x31: return "RVAE1"; + case 0x33: return "RVAAE1"; + case 0x35: return "RVALE1"; + case 0x37: return "RVAALE1"; + case 0x202: return "RIPAS2E1IS"; + case 0x206: return "RIPAS2LE1IS"; + case 0x208: return "ALLE2OS"; + case 0x209: return "VAE2OS"; + case 0x20c: return "ALLE1OS"; + case 0x20d: return "VALE2OS"; + case 0x20e: return "VMALLS12E1OS"; + case 0x211: return "RVAE2IS"; + case 0x215: return "RVALE2IS"; + case 0x220: return "IPAS2E1OS"; + default: return NULL; + }; +} + +static S32 DisassembleSystemInstr(struct instruction *i, struct ad_insn *out){ + U32 L = bits(i->opcode, 21, 21); + U32 op1 = bits(i->opcode, 16, 18); + U32 CRn = bits(i->opcode, 12, 15); + U32 CRm = bits(i->opcode, 8, 11); + U32 op2 = bits(i->opcode, 5, 7); + U32 Rt = bits(i->opcode, 0, 4); + + if(Rt > AD_RTBL_GEN_64_SZ) + return 1; + + ADD_FIELD(out, L); + ADD_FIELD(out, op1); + ADD_FIELD(out, CRn); + ADD_FIELD(out, CRm); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + if(L == 0){ + if(CRn == 7 && (CRm >> 1) == 4 && SysOp(op1, 7, CRm, op2) == Sys_AT){ + instr_id = AD_INSTR_AT; + + U32 encoding = (op1 << 4); + encoding |= ((CRm & 1) << 3); + encoding |= op2; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&encoding); + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + + const char *at_op_s = at_op(encoding); + + if(!at_op_s) + return 1; + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "at %s, %s", at_op_s, Rt_s); + } + else if(op1 == 3 && CRn == 7 && CRm == 3){ + const char *instr_s = NULL; + + if(op2 == 2){ + instr_s = "cfp"; + instr_id = AD_INSTR_CFP; + } + else if(op2 == 5){ + instr_s = "dvp"; + instr_id = AD_INSTR_DVP; + } + else if(op2 == 7){ + instr_s = "cpp"; + instr_id = AD_INSTR_CPP; + } + else{ + return 1; + } + + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "%s rctx, %s", instr_s, Rt_s); + } + else if(CRn == 7 && SysOp(op1, 7, CRm, op2) == Sys_DC){ + instr_id = AD_INSTR_DC; + + U32 encoding = (op1 << 7); + encoding |= (CRm << 3); + encoding |= op2; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&encoding); + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + + const char *dc_op_s = dc_op(encoding); + + if(!dc_op_s) + return 1; + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "dc %s, %s", dc_op_s, Rt_s); + } + else if(CRn == 7 && SysOp(op1, 7, CRm, op2) == Sys_IC){ + instr_id = AD_INSTR_IC; + + U32 encoding = (op1 << 7); + encoding |= (CRm << 3); + encoding |= op2; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&encoding); + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + + const char *ic_op_s = ic_op(encoding); + + if(!ic_op_s) + return 1; + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "ic %s, %s", ic_op_s, Rt_s); + } + else if(CRn == 8 && SysOp(op1, 8, CRm, op2) == Sys_TLBI){ + instr_id = AD_INSTR_TLBI; + + U32 encoding = (op1 << 7); + encoding |= (CRm << 3); + encoding |= op2; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&encoding); + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + + const char *tlbi_op_s = tlbi_op(encoding); + + if(!tlbi_op_s) + return 1; + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "tlbi %s, %s", tlbi_op_s, Rt_s); + } + else{ + instr_id = AD_INSTR_SYS; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&op1); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRn); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRm); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&op2); + + concat(&DECODE_STR(out), "sys #%#x, C%d, C%d, #%#x", + op1, CRn, CRm, op2); + + if(Rt != 0x1f){ + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rt_s); + } + } + } + else{ + instr_id = AD_INSTR_SYSL; + + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&op1); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRn); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&CRm); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&op2); + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "sysl %s, #%#x, C%d, C%d, #%#x", Rt_s, op1, + CRn, CRm, op2); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static const char *get_sysreg(U32 encoding){ + switch(encoding){ + case 0xc081: return "ACTLR_EL1"; + case 0xe081: return "ACTLR_EL2"; + case 0xf081: return "ACTLR_EL3"; + case 0xc288: return "AFSR0_EL1"; + case 0xea88: return "AFSR0_EL12"; + case 0xe288: return "AFSR0_EL2"; + case 0xf288: return "AFSR0_EL3"; + case 0xc289: return "AFSR1_EL1"; + case 0xea89: return "AFSR1_EL12"; + case 0xe289: return "AFSR1_EL2"; + case 0xf289: return "AFSR1_EL3"; + case 0xc807: return "AIDR_EL1"; + case 0xc518: return "AMAIR_EL1"; + case 0xed18: return "AMAIR_EL12"; + case 0xe518: return "AMAIR_EL2"; + case 0xf518: return "AMAIR_EL3"; + case 0xde91: return "AMCFGR_EL0"; + case 0xde92: return "AMCGCR_EL0"; + case 0xde94: return "AMCNTENCLR0_EL0"; + case 0xde98: return "AMCNTENCLR1_EL0"; + case 0xde95: return "AMCNTENSET0_EL0"; + case 0xde99: return "AMCNTENSET1_EL0"; + case 0xde90: return "AMCR_EL0"; + case 0xde93: return "AMUSERENR_EL0"; + case 0xc111: return "APDAKeyHi_EL1"; + case 0xc110: return "APDAKeyLo_EL1"; + case 0xc113: return "APDBKeyHi_EL1"; + case 0xc112: return "APDBKeyLo_EL1"; + case 0xc119: return "APGAKeyHi_EL1"; + case 0xc118: return "APGAKeyLo_EL1"; + case 0xc109: return "APIAKeyHi_EL1"; + case 0xc108: return "APIAKeyLo_EL1"; + case 0xc10b: return "APIBKeyHi_EL1"; + case 0xc10a: return "APIBKeyLo_EL1"; + case 0xc802: return "CCSIDR2_EL1"; + case 0xc800: return "CCSIDR_EL1"; + case 0xc801: return "CLIDR_EL1"; + case 0xdf00: return "CNTFRQ_EL0"; + case 0xe708: return "CNTHCTL_EL2"; + case 0xe729: return "CNTHPS_CTL_EL2"; + case 0xe72a: return "CNTHPS_CVAL_EL2"; + case 0xe728: return "CNTHPS_TVAL_EL2"; + case 0xe711: return "CNTHP_CTL_EL2"; + case 0xe712: return "CNTHP_CVAL_EL2"; + case 0xe710: return "CNTHP_TVAL_EL2"; + case 0xe721: return "CNTHVS_CTL_EL2"; + case 0xe722: return "CNTHVS_CVAL_EL2"; + case 0xe720: return "CNTHVS_TVAL_EL2"; + case 0xe719: return "CNTHV_CTL_EL2"; + case 0xe71a: return "CNTHV_CVAL_EL2"; + case 0xe718: return "CNTHV_TVAL_EL2"; + case 0xc708: return "CNTKCTL_EL1"; + case 0xdf01: return "CNTPCT_EL0"; + case 0xff11: return "CNTPS_CTL_EL1"; + case 0xff12: return "CNTPS_CVAL_EL1"; + case 0xff10: return "CNTPS_TVAL_EL1"; + case 0xdf11: return "CNTP_CTL_EL0"; + case 0xef11: return "CNTP_CTL_EL02"; + case 0xdf12: return "CNTP_CVAL_EL0"; + case 0xef12: return "CNTP_CVAL_EL02"; + case 0xdf10: return "CNTP_TVAL_EL0"; + case 0xef10: return "CNTP_TVAL_EL02"; + case 0xdf02: return "CNTVCT_EL0"; + case 0xe703: return "CNTVOFF_EL2"; + case 0xdf19: return "CNTV_CTL_EL0"; + case 0xef19: return "CNTV_CTL_EL02"; + case 0xdf1a: return "CNTV_CVAL_EL0"; + case 0xef1a: return "CNTV_CVAL_EL02"; + case 0xdf18: return "CNTV_TVAL_EL0"; + case 0xef18: return "CNTV_TVAL_EL02"; + case 0xc681: return "CONTEXTIDR_EL1"; + case 0xee81: return "CONTEXTIDR_EL12"; + case 0xe681: return "CONTEXTIDR_EL2"; + case 0xc082: return "CPACR_EL1"; + case 0xe882: return "CPACR_EL12"; + case 0xe08a: return "CPTR_EL2"; + case 0xf08a: return "CPTR_EL3"; + case 0xd000: return "CSSELR_EL1"; + case 0xd801: return "CTR_EL0"; + case 0xc212: return "CurrentEL"; + case 0xe180: return "DACR32_EL2"; + case 0xda11: return "DAIF"; + case 0x83f6: return "DBGAUTHSTATUS_EL1"; + case 0x83ce: return "DBGCLAIMCLR_EL1"; + case 0x83c6: return "DBGCLAIMSET_EL1"; + case 0x9828: return "DBGDTRRX_EL0"; /* DBGDTRTX_EL0 has same encoding */ + case 0x9820: return "DBGDTR_EL0"; + case 0x80a4: return "DBGPRCR_EL1"; + case 0xa038: return "DBGVCR32_EL2"; + case 0xd807: return "DCZID_EL0"; + case 0xc609: return "DISR_EL1"; + case 0xda15: return "DIT"; + case 0xda29: return "DLR_EL0"; + case 0xda28: return "DSPSR_EL0"; + case 0xc201: return "ELR_EL1"; + case 0xea01: return "ELR_EL12"; + case 0xe201: return "ELR_EL2"; + case 0xf201: return "ELR_EL3"; + case 0xc298: return "ERRIDR_EL1"; + case 0xc299: return "ERRSELR_EL1"; + case 0xc2a3: return "ERXADDR_EL1"; + case 0xc2a1: return "ERXCTLR_EL1"; + case 0xc2a0: return "ERXFR_EL1"; + case 0xc2a8: return "ERXMISC0_EL1"; + case 0xc2a9: return "ERXMISC1_EL1"; + case 0xc2aa: return "ERXMISC2_EL1"; + case 0xc2ab: return "ERXMISC3_EL1"; + case 0xc2a6: return "ERXPFGCDN_EL1"; + case 0xc2a5: return "ERXPFGCTL_EL1"; + case 0xc2a4: return "ERXPFGF_EL1"; + case 0xc2a2: return "ERXSTATUS_EL1"; + case 0xc290: return "ESR_EL1"; + case 0xea90: return "ESR_EL12"; + case 0xe290: return "ESR_EL2"; + case 0xf290: return "ESR_EL3"; + case 0xc300: return "FAR_EL1"; + case 0xeb00: return "FAR_EL12"; + case 0xe300: return "FAR_EL2"; + case 0xf300: return "FAR_EL3"; + case 0xd184: return "FPCR"; + case 0xe298: return "FPEXC32_EL2"; + case 0xd194: return "FPSR"; + case 0xc086: return "GCR_EL1"; + case 0xcc0: return "GMID_EL1"; + case 0xe08f: return "HACR_EL2"; + case 0xe088: return "HCR_EL2"; + case 0xe304: return "HPFAR_EL2"; + case 0xe08b: return "HSTR_EL2"; + case 0xc02c: return "ID_AA64AFR0_EL1"; + case 0xc02d: return "ID_AA64AFR1_EL1"; + case 0xc028: return "ID_AA64DFR0_EL1"; + case 0xc029: return "ID_AA64DFR1_EL1"; + case 0xc030: return "ID_AA64ISAR0_EL1"; + case 0xc031: return "ID_AA64ISAR1_EL1"; + case 0xc038: return "ID_AA64MMFR0_EL1"; + case 0xc039: return "ID_AA64MMFR1_EL1"; + case 0xc03a: return "ID_AA64MMFR2_EL1"; + case 0xc020: return "ID_AA64PFR0_EL1"; + case 0xc021: return "ID_AA64PFR1_EL1"; + case 0xc00b: return "ID_AFR0_EL1"; + case 0xc00a: return "ID_DFR0_EL1"; + case 0xc010: return "ID_ISAR0_EL1"; + case 0xc011: return "ID_ISAR1_EL1"; + case 0xc012: return "ID_ISAR2_EL1"; + case 0xc013: return "ID_ISAR3_EL1"; + case 0xc014: return "ID_ISAR4_EL1"; + case 0xc015: return "ID_ISAR5_EL1"; + case 0xc017: return "ID_ISAR6_EL1"; + case 0xc00c: return "ID_MMFR0_EL1"; + case 0xc00d: return "ID_MMFR1_EL1"; + case 0xc00e: return "ID_MMFR2_EL1"; + case 0xc00f: return "ID_MMFR3_EL1"; + case 0xc016: return "ID_MMFR4_EL1"; + case 0xc008: return "ID_PFR0_EL1"; + case 0xc009: return "ID_PFR1_EL1"; + case 0xc01c: return "ID_PFR2_EL1"; + case 0xe281: return "IFSR32_EL2"; + case 0xc608: return "ISR_EL1"; + case 0xc523: return "LORC_EL1"; + case 0xc521: return "LOREA_EL1"; + case 0xc527: return "LORID_EL1"; + case 0xc522: return "LORN_EL1"; + case 0xc520: return "LORSA_EL1"; + case 0xc510: return "MAIR_EL1"; + case 0xed10: return "MAIR_EL12"; + case 0xe510: return "MAIR_EL2"; + case 0xf510: return "MAIR_EL3"; + case 0x8010: return "MDCCINT_EL1"; + case 0x9808: return "MDCCSR_EL0"; + case 0xe089: return "MDCR_EL2"; + case 0xf099: return "MDCR_EL3"; + case 0x8080: return "MDRAR_EL1"; + case 0x8012: return "MDSCR_EL1"; + case 0xc000: return "MIDR_EL1"; + case 0xc005: return "MPIDR_EL1"; + case 0xc018: return "MVFR0_EL1"; + case 0xc019: return "MVFR1_EL1"; + case 0xc01a: return "MVFR2_EL1"; + case 0xda10: return "NZCV"; + case 0x809c: return "OSDLR_EL1"; + case 0x8002: return "OSDTRRX_EL1"; + case 0x801a: return "OSDTRTX_EL1"; + case 0x8032: return "OSECCR_EL1"; + case 0x8084: return "OSLAR_EL1"; + case 0x808c: return "OSLSR_EL1"; + case 0xc213: return "PAN"; + case 0xc3a0: return "PAR_EL1"; + case 0xc4d7: return "PMBIDR_EL1"; + case 0xc4d0: return "PMBLIMITR_EL1"; + case 0xc4d1: return "PMBPTR_EL1"; + case 0xc4d3: return "PMBSR_EL1"; + case 0xdf7f: return "PMCCFILTR_EL0"; + case 0xdce8: return "PMCCNTR_EL0"; + case 0xdce6: return "PMCEID0_EL0"; + case 0xdce7: return "PMCEID1_EL0"; + case 0xdce2: return "PMCNTENCLR_EL0"; + case 0xdce1: return "PMCNTENSET_EL0"; + case 0xdce0: return "PMCR_EL0"; + case 0xc4f2: return "PMINTENCLR_EL1"; + case 0xc4f1: return "PMINTENSET_EL1"; + case 0xc4f6: return "PMMIR_EL1"; + case 0xdce3: return "PMOVSCLR_EL0"; + case 0xdcf3: return "PMOVSSET_EL0"; + case 0xc4c8: return "PMSCR_EL1"; + case 0xecc8: return "PMSCR_EL12"; + case 0xe4c8: return "PMSCR_EL2"; + case 0xdce5: return "PMSELR_EL0"; + case 0xc4cd: return "PMSEVFR_EL1"; + case 0xc4cc: return "PMSFCR_EL1"; + case 0xc4ca: return "PMSICR_EL1"; + case 0xc4cf: return "PMSIDR_EL1"; + case 0xc4cb: return "PMSIRR_EL1"; + case 0xc4ce: return "PMSLATFR_EL1"; + case 0xdce4: return "PMSWINC_EL0"; + case 0xdcf0: return "PMUSERENR_EL0"; + case 0xdcea: return "PMXEVCNTR_EL0"; + case 0xdce9: return "PMXEVTYPER_EL0"; + case 0xc006: return "REVIDR_EL1"; + case 0xc085: return "RGSR_EL1"; + case 0xc602: return "RMR_EL1"; + case 0xe602: return "RMR_EL2"; + case 0xf602: return "RMR_EL3"; + case 0xd920: return "RNDR"; + case 0xd921: return "RNDRRS"; + case 0xc601: return "RVBAR_EL1"; + case 0xe601: return "RVBAR_EL2"; + case 0xf601: return "RVBAR_EL3"; + case 0xf088: return "SCR_EL3"; + case 0xc080: return "SCTLR_EL1"; + case 0xe880: return "SCTLR_EL12"; + case 0xe080: return "SCTLR_EL2"; + case 0xf080: return "SCTLR_EL3"; + case 0xde87: return "SCXTNUM_EL0"; + case 0xc687: return "SCXTNUM_EL1"; + case 0xee87: return "SCXTNUM_EL12"; + case 0xe687: return "SCXTNUM_EL2"; + case 0xf687: return "SCXTNUM_EL3"; + case 0xe099: return "SDER32_EL2"; + case 0xf089: return "SDER32_EL3"; + case 0xc200: return "SPSR_EL1"; + case 0xea00: return "SPSR_EL12"; + case 0xe200: return "SPSR_EL2"; + case 0xf200: return "SPSR_EL3"; + case 0xe219: return "SPSR_abt"; + case 0xe21b: return "SPSR_fiq"; + case 0xe218: return "SPSR_irq"; + case 0xe21a: return "SPSR_und"; + case 0xc210: return "SPSel"; + case 0xc208: return "SP_EL0"; + case 0xe208: return "SP_EL1"; + case 0xf208: return "SP_EL2"; + case 0xda16: return "SSBS"; + case 0xda17: return "TCO"; + case 0xc102: return "TCR_EL1"; + case 0xe902: return "TCR_EL12"; + case 0xe102: return "TCR_EL2"; + case 0xf102: return "TCR_EL3"; + case 0xc2b1: return "TFSRE0_EL1"; + case 0xc2b0: return "TFSR_EL1"; + case 0xeab0: return "TFSR_EL12"; + case 0xe2b0: return "TFSR_EL2"; + case 0xf2b0: return "TFSR_EL3"; + case 0xde83: return "TPIDRRO_EL0"; + case 0xde82: return "TPIDR_EL0"; + case 0xc684: return "TPIDR_EL1"; + case 0xe682: return "TPIDR_EL2"; + case 0xf682: return "TPIDR_EL3"; + case 0xc091: return "TRFCR_EL1"; + case 0xe891: return "TRFCR_EL12"; + case 0xe091: return "TRFCR_EL2"; + case 0xc100: return "TTBR0_EL1"; + case 0xe900: return "TTBR0_EL12"; + case 0xe100: return "TTBR0_EL2"; + case 0xf100: return "TTBR0_EL3"; + case 0xc101: return "TTBR1_EL1"; + case 0xe901: return "TTBR1_EL12"; + case 0xe101: return "TTBR1_EL2"; + case 0xc214: return "UAO"; + case 0xc600: return "VBAR_EL1"; + case 0xee00: return "VBAR_EL12"; + case 0xe600: return "VBAR_EL2"; + case 0xf600: return "VBAR_EL3"; + case 0xe609: return "VDISR_EL2"; + case 0xe005: return "VMPIDR_EL2"; + case 0xe110: return "VNCR_EL2"; + case 0xe000: return "VPIDR_EL2"; + case 0xe293: return "VSESR_EL2"; + case 0xe132: return "VSTCR_EL2"; + case 0xe130: return "VSTTBR_EL2"; + case 0xe10a: return "VTCR_EL2"; + case 0xe108: return "VTTBR_EL2"; + case 0xdea0: return "AMEVCNTR00_EL0"; + case 0xdea1: return "AMEVCNTR01_EL0"; + case 0xdea2: return "AMEVCNTR02_EL0"; + case 0xdea3: return "AMEVCNTR03_EL0"; + case 0xdea4: return "AMEVCNTR04_EL0"; + case 0xdea5: return "AMEVCNTR05_EL0"; + case 0xdea6: return "AMEVCNTR06_EL0"; + case 0xdea7: return "AMEVCNTR07_EL0"; + case 0xdea8: return "AMEVCNTR08_EL0"; + case 0xdea9: return "AMEVCNTR09_EL0"; + case 0xdeaa: return "AMEVCNTR010_EL0"; + case 0xdeab: return "AMEVCNTR011_EL0"; + case 0xdeac: return "AMEVCNTR012_EL0"; + case 0xdead: return "AMEVCNTR013_EL0"; + case 0xdeae: return "AMEVCNTR014_EL0"; + case 0xdeaf: return "AMEVCNTR015_EL0"; + case 0xdee0: return "AMEVCNTR10_EL0"; + case 0xdee1: return "AMEVCNTR11_EL0"; + case 0xdee2: return "AMEVCNTR12_EL0"; + case 0xdee3: return "AMEVCNTR13_EL0"; + case 0xdee4: return "AMEVCNTR14_EL0"; + case 0xdee5: return "AMEVCNTR15_EL0"; + case 0xdee6: return "AMEVCNTR16_EL0"; + case 0xdee7: return "AMEVCNTR17_EL0"; + case 0xdee8: return "AMEVCNTR18_EL0"; + case 0xdee9: return "AMEVCNTR19_EL0"; + case 0xdeea: return "AMEVCNTR110_EL0"; + case 0xdeeb: return "AMEVCNTR111_EL0"; + case 0xdeec: return "AMEVCNTR112_EL0"; + case 0xdeed: return "AMEVCNTR113_EL0"; + case 0xdeee: return "AMEVCNTR114_EL0"; + case 0xdeef: return "AMEVCNTR115_EL0"; + case 0xdeb0: return "AMEVTYPER00_EL0"; + case 0xdeb1: return "AMEVTYPER01_EL0"; + case 0xdeb2: return "AMEVTYPER02_EL0"; + case 0xdeb3: return "AMEVTYPER03_EL0"; + case 0xdeb4: return "AMEVTYPER04_EL0"; + case 0xdeb5: return "AMEVTYPER05_EL0"; + case 0xdeb6: return "AMEVTYPER06_EL0"; + case 0xdeb7: return "AMEVTYPER07_EL0"; + case 0xdeb8: return "AMEVTYPER08_EL0"; + case 0xdeb9: return "AMEVTYPER09_EL0"; + case 0xdeba: return "AMEVTYPER010_EL0"; + case 0xdebb: return "AMEVTYPER011_EL0"; + case 0xdebc: return "AMEVTYPER012_EL0"; + case 0xdebd: return "AMEVTYPER013_EL0"; + case 0xdebe: return "AMEVTYPER014_EL0"; + case 0xdebf: return "AMEVTYPER015_EL0"; + case 0xdef0: return "AMEVTYPER10_EL0"; + case 0xdef1: return "AMEVTYPER11_EL0"; + case 0xdef2: return "AMEVTYPER12_EL0"; + case 0xdef3: return "AMEVTYPER13_EL0"; + case 0xdef4: return "AMEVTYPER14_EL0"; + case 0xdef5: return "AMEVTYPER15_EL0"; + case 0xdef6: return "AMEVTYPER16_EL0"; + case 0xdef7: return "AMEVTYPER17_EL0"; + case 0xdef8: return "AMEVTYPER18_EL0"; + case 0xdef9: return "AMEVTYPER19_EL0"; + case 0xdefa: return "AMEVTYPER110_EL0"; + case 0xdefb: return "AMEVTYPER111_EL0"; + case 0xdefc: return "AMEVTYPER112_EL0"; + case 0xdefd: return "AMEVTYPER113_EL0"; + case 0xdefe: return "AMEVTYPER114_EL0"; + case 0xdeff: return "AMEVTYPER115_EL0"; + case 0x8005: return "DBGBCR0_EL1"; + case 0x800d: return "DBGBCR1_EL1"; + case 0x8015: return "DBGBCR2_EL1"; + case 0x801d: return "DBGBCR3_EL1"; + case 0x8025: return "DBGBCR4_EL1"; + case 0x802d: return "DBGBCR5_EL1"; + case 0x8035: return "DBGBCR6_EL1"; + case 0x803d: return "DBGBCR7_EL1"; + case 0x8045: return "DBGBCR8_EL1"; + case 0x804d: return "DBGBCR9_EL1"; + case 0x8055: return "DBGBCR10_EL1"; + case 0x805d: return "DBGBCR11_EL1"; + case 0x8065: return "DBGBCR12_EL1"; + case 0x806d: return "DBGBCR13_EL1"; + case 0x8075: return "DBGBCR14_EL1"; + case 0x807d: return "DBGBCR15_EL1"; + case 0x8004: return "DBGBVR0_EL1"; + case 0x800c: return "DBGBVR1_EL1"; + case 0x8014: return "DBGBVR2_EL1"; + case 0x801c: return "DBGBVR3_EL1"; + case 0x8024: return "DBGBVR4_EL1"; + case 0x802c: return "DBGBVR5_EL1"; + case 0x8034: return "DBGBVR6_EL1"; + case 0x803c: return "DBGBVR7_EL1"; + case 0x8044: return "DBGBVR8_EL1"; + case 0x804c: return "DBGBVR9_EL1"; + case 0x8054: return "DBGBVR10_EL1"; + case 0x805c: return "DBGBVR11_EL1"; + case 0x8064: return "DBGBVR12_EL1"; + case 0x806c: return "DBGBVR13_EL1"; + case 0x8074: return "DBGBVR14_EL1"; + case 0x807c: return "DBGBVR15_EL1"; + case 0x8007: return "DBGWCR0_EL1"; + case 0x800f: return "DBGWCR1_EL1"; + case 0x8017: return "DBGWCR2_EL1"; + case 0x801f: return "DBGWCR3_EL1"; + case 0x8027: return "DBGWCR4_EL1"; + case 0x802f: return "DBGWCR5_EL1"; + case 0x8037: return "DBGWCR6_EL1"; + case 0x803f: return "DBGWCR7_EL1"; + case 0x8047: return "DBGWCR8_EL1"; + case 0x804f: return "DBGWCR9_EL1"; + case 0x8057: return "DBGWCR10_EL1"; + case 0x805f: return "DBGWCR11_EL1"; + case 0x8067: return "DBGWCR12_EL1"; + case 0x806f: return "DBGWCR13_EL1"; + case 0x8077: return "DBGWCR14_EL1"; + case 0x807f: return "DBGWCR15_EL1"; + case 0x8006: return "DBGWVR0_EL1"; + case 0x800e: return "DBGWVR1_EL1"; + case 0x8016: return "DBGWVR2_EL1"; + case 0x801e: return "DBGWVR3_EL1"; + case 0x8026: return "DBGWVR4_EL1"; + case 0x802e: return "DBGWVR5_EL1"; + case 0x8036: return "DBGWVR6_EL1"; + case 0x803e: return "DBGWVR7_EL1"; + case 0x8046: return "DBGWVR8_EL1"; + case 0x804e: return "DBGWVR9_EL1"; + case 0x8056: return "DBGWVR10_EL1"; + case 0x805e: return "DBGWVR11_EL1"; + case 0x8066: return "DBGWVR12_EL1"; + case 0x806e: return "DBGWVR13_EL1"; + case 0x8076: return "DBGWVR14_EL1"; + case 0x807e: return "DBGWVR15_EL1"; + case 0xdf40: return "PMEVCNTR0_EL0"; + case 0xdf41: return "PMEVCNTR1_EL0"; + case 0xdf42: return "PMEVCNTR2_EL0"; + case 0xdf43: return "PMEVCNTR3_EL0"; + case 0xdf44: return "PMEVCNTR4_EL0"; + case 0xdf45: return "PMEVCNTR5_EL0"; + case 0xdf46: return "PMEVCNTR6_EL0"; + case 0xdf47: return "PMEVCNTR7_EL0"; + case 0xdf48: return "PMEVCNTR8_EL0"; + case 0xdf49: return "PMEVCNTR9_EL0"; + case 0xdf4a: return "PMEVCNTR10_EL0"; + case 0xdf4b: return "PMEVCNTR11_EL0"; + case 0xdf4c: return "PMEVCNTR12_EL0"; + case 0xdf4d: return "PMEVCNTR13_EL0"; + case 0xdf4e: return "PMEVCNTR14_EL0"; + case 0xdf4f: return "PMEVCNTR15_EL0"; + case 0xdf50: return "PMEVCNTR16_EL0"; + case 0xdf51: return "PMEVCNTR17_EL0"; + case 0xdf52: return "PMEVCNTR18_EL0"; + case 0xdf53: return "PMEVCNTR19_EL0"; + case 0xdf54: return "PMEVCNTR20_EL0"; + case 0xdf55: return "PMEVCNTR21_EL0"; + case 0xdf56: return "PMEVCNTR22_EL0"; + case 0xdf57: return "PMEVCNTR23_EL0"; + case 0xdf58: return "PMEVCNTR24_EL0"; + case 0xdf59: return "PMEVCNTR25_EL0"; + case 0xdf5a: return "PMEVCNTR26_EL0"; + case 0xdf5b: return "PMEVCNTR27_EL0"; + case 0xdf5c: return "PMEVCNTR28_EL0"; + case 0xdf5d: return "PMEVCNTR29_EL0"; + case 0xdf5e: return "PMEVCNTR30_EL0"; + case 0xdf5f: return "PMEVCNTR31_EL0"; + case 0xdf60: return "PMEVTYPER0_EL0"; + case 0xdf61: return "PMEVTYPER1_EL0"; + case 0xdf62: return "PMEVTYPER2_EL0"; + case 0xdf63: return "PMEVTYPER3_EL0"; + case 0xdf64: return "PMEVTYPER4_EL0"; + case 0xdf65: return "PMEVTYPER5_EL0"; + case 0xdf66: return "PMEVTYPER6_EL0"; + case 0xdf67: return "PMEVTYPER7_EL0"; + case 0xdf68: return "PMEVTYPER8_EL0"; + case 0xdf69: return "PMEVTYPER9_EL0"; + case 0xdf6a: return "PMEVTYPER10_EL0"; + case 0xdf6b: return "PMEVTYPER11_EL0"; + case 0xdf6c: return "PMEVTYPER12_EL0"; + case 0xdf6d: return "PMEVTYPER13_EL0"; + case 0xdf6e: return "PMEVTYPER14_EL0"; + case 0xdf6f: return "PMEVTYPER15_EL0"; + case 0xdf70: return "PMEVTYPER16_EL0"; + case 0xdf71: return "PMEVTYPER17_EL0"; + case 0xdf72: return "PMEVTYPER18_EL0"; + case 0xdf73: return "PMEVTYPER19_EL0"; + case 0xdf74: return "PMEVTYPER20_EL0"; + case 0xdf75: return "PMEVTYPER21_EL0"; + case 0xdf76: return "PMEVTYPER22_EL0"; + case 0xdf77: return "PMEVTYPER23_EL0"; + case 0xdf78: return "PMEVTYPER24_EL0"; + case 0xdf79: return "PMEVTYPER25_EL0"; + case 0xdf7a: return "PMEVTYPER26_EL0"; + case 0xdf7b: return "PMEVTYPER27_EL0"; + case 0xdf7c: return "PMEVTYPER28_EL0"; + case 0xdf7d: return "PMEVTYPER29_EL0"; + case 0xdf7e: return "PMEVTYPER30_EL0"; + default: return NULL; + }; +} + +static S32 DisassembleSystemRegisterMoveInstr(struct instruction *i, + struct ad_insn *out){ + U32 L = bits(i->opcode, 21, 21); + U32 o0 = bits(i->opcode, 19, 19); + U32 op1 = bits(i->opcode, 16, 18); + U32 CRn = bits(i->opcode, 12, 15); + U32 CRm = bits(i->opcode, 8, 11); + U32 op2 = bits(i->opcode, 5, 7); + U32 Rt = bits(i->opcode, 0, 4); + + if(Rt > AD_RTBL_GEN_64_SZ) + return 1; + + ADD_FIELD(out, L); + ADD_FIELD(out, o0); + ADD_FIELD(out, op1); + ADD_FIELD(out, CRn); + ADD_FIELD(out, CRm); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rt); + + S32 instr_id = L == 0 ? AD_INSTR_MSR : AD_INSTR_MRS; + + U32 sreg = ((2 + o0) << 14); + sreg |= (op1 << 11); + sreg |= (CRn << 7); + sreg |= (CRm << 3); + sreg |= op2; + + const char *sreg_s = get_sysreg(sreg); + S32 free_sreg_s = 0; + + /* if we couldn't get it, this system reg is implementation defined */ + if(!sreg_s){ + free_sreg_s = 1; + concat((char **)&sreg_s, "S%d_%d_C%d_C%d_%d", 2 + o0, op1, CRn, CRm, op2); + } + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, PREFER_ZR); + + if(instr_id == AD_INSTR_MRS){ + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), PREFER_ZR, _SYSREG(sreg), _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), "mrs %s, %s", Rt_s, sreg_s); + } + else{ + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), PREFER_ZR, _SYSREG(sreg), _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), "msr %s, %s", sreg_s, Rt_s); + } + + if(free_sreg_s){ + free((char *)sreg_s); + sreg_s = NULL; + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleUnconditionalBranchRegisterInstr(struct instruction *i, + struct ad_insn *out){ + U32 opc = bits(i->opcode, 21, 24); + U32 op2 = bits(i->opcode, 16, 20); + U32 op3 = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 op4 = bits(i->opcode, 0, 4); + + if(op2 != 0x1f) + return 1; + + ADD_FIELD(out, opc); + ADD_FIELD(out, op2); + ADD_FIELD(out, op3); + ADD_FIELD(out, Rn); + ADD_FIELD(out, op4); + + S32 instr_id = AD_NONE; + + if((opc == 0 || opc == 1) || (opc == 8 || opc == 9)){ + const char *instr_s = NULL; + + if((opc == 0 || opc == 1) && (op3 == 0 && op4 == 0)){ + instr_s = opc == 0 ? "br" : "blr"; + instr_id = opc == 0 ? AD_INSTR_BR : AD_INSTR_BLR; + } + else if((opc == 0 || opc == 1) && op4 == 0x1f){ + if(opc == 0){ + instr_s = op3 == 2 ? "braaz" : "brabz"; + instr_id = op3 == 2 ? AD_INSTR_BRAAZ : AD_INSTR_BRABZ; + } + else{ + instr_s = op3 == 2 ? "blraaz" : "blrabz"; + instr_id = op3 == 2 ? AD_INSTR_BLRAAZ : AD_INSTR_BLRABZ; + } + } + else if(opc == 8 || opc == 9){ + if(opc == 8){ + instr_s = op3 == 2 ? "braa" : "brab"; + instr_id = op3 == 2 ? AD_INSTR_BRAA : AD_INSTR_BRAB; + } + else{ + instr_s = op3 == 2 ? "blraa" : "blrab"; + instr_id = op3 == 2 ? AD_INSTR_BLRAA : AD_INSTR_BLRAB; + } + } + + if(!instr_s) + return 1; + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rn_s); + + if(opc == 8 || opc == 9){ + U32 Rm = op4; + + ADD_REG_OPERAND(out, Rm, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + const char *Rm_s = GET_GEN_REG(AD_RTBL_GEN_64, Rm, NO_PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + } + else if(opc == 2 || opc == 4){ + const char *instr_s = NULL; + + if(op3 == 0 && op4 == 0){ + instr_s = opc == 2 ? "ret" : "eret"; + instr_id = opc == 2 ? AD_INSTR_RET : AD_INSTR_ERET; + } + else if(op4 == 0x1f){ + if(opc == 2){ + instr_s = op3 == 2 ? "retaa" : "retab"; + instr_id = op3 == 2 ? AD_INSTR_RETAA : AD_INSTR_RETAB; + } + else{ + instr_s = op3 == 2 ? "eretaa" : "eretab"; + instr_id = op3 == 2 ? AD_INSTR_ERETAA : AD_INSTR_ERETAB; + } + } + + if(!instr_s) + return 1; + + concat(&DECODE_STR(out), "%s", instr_s); + + if(instr_id == AD_INSTR_RET && Rn != 0x1e){ + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rn_s); + } + } + else if(opc == 5){ + instr_id = AD_INSTR_DRPS; + + concat(&DECODE_STR(out), "drps"); + } + else{ + return 1; + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleUnconditionalBranchImmInstr(struct instruction *i, + struct ad_insn *out){ + U32 op = bits(i->opcode, 31, 31); + U32 imm26 = bits(i->opcode, 0, 25); + + ADD_FIELD(out, op); + ADD_FIELD(out, imm26); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(op == 0){ + instr_s = "b"; + instr_id = AD_INSTR_B; + } + else{ + instr_s = "bl"; + instr_id = AD_INSTR_BL; + } + + imm26 = sign_extend(imm26 << 2, 28); + + S64 imm = (S64)imm26 + i->PC; + + ADD_IMM_OPERAND(out, AD_IMM_LONG, *(S64 *)&imm); + + concat(&DECODE_STR(out), "%s "S_LX"", instr_s, S_LA(imm)); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleCompareAndBranchImmediateInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 24, 24); + U32 imm19 = bits(i->opcode, 5, 23); + U32 Rt = bits(i->opcode, 0, 4); + + const char **registers = AD_RTBL_GEN_32; + size_t len = AD_RTBL_GEN_32_SZ; + + if(sf == 1){ + registers = AD_RTBL_GEN_64; + len = AD_RTBL_GEN_64_SZ; + } + + if(Rt > len) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, imm19); + ADD_FIELD(out, Rt); + + const char *Rt_s = GET_GEN_REG(registers, Rt, NO_PREFER_ZR); + + const char *instr_s = op == 0 ? "cbz" : "cbnz"; + S32 instr_id = op == 0 ? AD_INSTR_CBZ : AD_INSTR_CBNZ; + S32 sz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + + imm19 = sign_extend(imm19 << 2, 21); + + S64 imm = (S64)imm19 + i->PC; + + ADD_REG_OPERAND(out, Rt, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_LONG, *(S64 *)&imm); + + concat(&DECODE_STR(out), "%s %s, "S_LX"", instr_s, Rt_s, S_LA(imm)); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleTestAndBranchImmediateInstr(struct instruction *i, + struct ad_insn *out){ + U32 b5 = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 24, 24); + U32 b40 = bits(i->opcode, 19, 23); + U32 imm14 = bits(i->opcode, 5, 18); + U32 Rt = bits(i->opcode, 0, 4); + + const char **registers = AD_RTBL_GEN_32; + size_t len = AD_RTBL_GEN_32_SZ; + + if(b5 == 1){ + registers = AD_RTBL_GEN_64; + len = AD_RTBL_GEN_64_SZ; + } + + if(Rt > len) + return 1; + + ADD_FIELD(out, b5); + ADD_FIELD(out, op); + ADD_FIELD(out, b40); + ADD_FIELD(out, imm14); + ADD_FIELD(out, Rt); + + const char *Rt_s = GET_GEN_REG(registers, Rt, PREFER_ZR); + + const char *instr_s = op == 0 ? "tbz" : "tbnz"; + S32 instr_id = op == 0 ? AD_INSTR_TBZ : AD_INSTR_TBNZ; + S32 sz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + + U32 bit_pos = (b5 << 6) | b40; + + imm14 = sign_extend(imm14 << 2, 16); + + S64 imm = (signed)imm14 + i->PC; + + ADD_REG_OPERAND(out, Rt, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&bit_pos); + ADD_IMM_OPERAND(out, AD_IMM_LONG, *(long *)&imm); + + concat(&DECODE_STR(out), "%s %s, #%#x, #"S_LX"", instr_s, Rt_s, bit_pos, S_LA(imm)); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +S32 BranchExcSysDisassemble(struct instruction *i, struct ad_insn *out){ + U32 op0 = bits(i->opcode, 29, 31); + U32 op1 = bits(i->opcode, 12, 25); + U32 op2 = bits(i->opcode, 0, 4); + + S32 result = 0; + + if(op0 == 2) + result = DisassembleConditionalImmediateBranchInstr(i, out); + else if(op0 == 6){ + if((op1 >> 12) == 0) + result = DisassembleExcGenInstr(i, out); + else if(op1 == 0x1032 && op2 == 0x1f) + result = DisassembleHintInstr(i, out); + else if(op1 == 0x1033) + result = DisassembleBarrierInstr(i, out); + else if((op1 & ~0x70) == 0x1004) + result = DisassemblePSTATEInstr(i, out); + else if(((op1 >> 7) & ~4) == 0x21) + result = DisassembleSystemInstr(i, out); + else if(((op1 >> 8) & ~2) == 0x11) + result = DisassembleSystemRegisterMoveInstr(i, out); + else if((op1 >> 13) == 1) + result = DisassembleUnconditionalBranchRegisterInstr(i, out); + else + result = 1; + } + else if((op0 & ~4) == 0){ + result = DisassembleUnconditionalBranchImmInstr(i, out); + } + else if((op0 & ~4) == 1){ + if((op1 >> 13) == 0) + result = DisassembleCompareAndBranchImmediateInstr(i, out); + else + result = DisassembleTestAndBranchImmediateInstr(i, out); + } + else{ + result = 1; + } + + return result; +} diff --git a/src/third_party/armadillo/source/BranchExcSys.h b/src/third_party/armadillo/source/BranchExcSys.h new file mode 100644 index 000000000..628077ea3 --- /dev/null +++ b/src/third_party/armadillo/source/BranchExcSys.h @@ -0,0 +1,6 @@ +#ifndef _BRANCHEXCSYS_H_ +#define _BRANCHEXCSYS_H_ + +S32 BranchExcSysDisassemble(struct instruction *, struct ad_insn *); + +#endif diff --git a/src/third_party/armadillo/source/DataProcessingFloatingPoint.c b/src/third_party/armadillo/source/DataProcessingFloatingPoint.c new file mode 100644 index 000000000..1e2d1fc60 --- /dev/null +++ b/src/third_party/armadillo/source/DataProcessingFloatingPoint.c @@ -0,0 +1,5206 @@ +#include +#include + +#include "adefs.h" +#include "bits.h" +#include "common.h" +#include "instruction.h" +#include "utils.h" +#include "strext.h" + +static S32 DisassembleCryptographicAESInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 22, 23); + U32 opcode = bits(i->opcode, 12, 16); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(size != 0) + return 1; + + ADD_FIELD(out, size); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + { "aese", AD_INSTR_AESE }, { "aesd", AD_INSTR_AESD }, + { "aesmc", AD_INSTR_AESMC }, { "aesimc", AD_INSTR_AESIMC } + }; + + opcode -= 4; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + S32 instr_id = tab[opcode].instr_id; + + const char **registers = AD_RTBL_FP_V_128; + S32 sz = _128_BIT; + + ADD_REG_OPERAND(out, Rd, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + const char *Rd_s = GET_FP_REG(registers, Rd); + const char *Rn_s = GET_FP_REG(registers, Rn); + + concat(&DECODE_STR(out), "%s %s.16b, %s.16b", instr_s, Rd_s, Rn_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleCryptographicThreeRegisterSHAInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 12, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(size != 0) + return 1; + + ADD_FIELD(out, size); + ADD_FIELD(out, Rm); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + { "sha1c", AD_INSTR_SHA1C }, { "sha1p", AD_INSTR_SHA1P }, + { "sha1m", AD_INSTR_SHA1M }, { "sha1su0", AD_INSTR_SHA1SU0 }, + { "sha256h", AD_INSTR_SHA256H }, { "sha256h2", AD_INSTR_SHA256H2 }, + { "sha256su1", AD_INSTR_SHA256SU1 } + }; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + S32 instr_id = tab[opcode].instr_id; + + concat(&DECODE_STR(out), "%s", instr_s); + + if(instr_id != AD_INSTR_SHA1SU0 && instr_id != AD_INSTR_SHA256SU1){ + const char *Rd_s = GET_FP_REG(AD_RTBL_FP_128, Rd); + ADD_REG_OPERAND(out, Rd, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_128)); + + concat(&DECODE_STR(out), " %s", Rd_s); + + const char *Rn_s = NULL; + + if(instr_id == AD_INSTR_SHA256H || instr_id == AD_INSTR_SHA256H2){ + Rn_s = GET_FP_REG(AD_RTBL_FP_128, Rn); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_128)); + + concat(&DECODE_STR(out), ", %s", Rn_s); + } + else{ + Rn_s = GET_FP_REG(AD_RTBL_FP_32, Rn); + ADD_REG_OPERAND(out, Rn, _SZ(_32_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_32)); + + concat(&DECODE_STR(out), ", %s", Rn_s); + } + } + else{ + const char *Rd_s = GET_FP_REG(AD_RTBL_FP_V_128, Rd); + ADD_REG_OPERAND(out, Rd, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_V_128, Rn); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + concat(&DECODE_STR(out), " %s.4s, %s.4s", Rd_s, Rn_s); + } + + const char *Rm_s = GET_FP_REG(AD_RTBL_FP_V_128, Rm); + ADD_REG_OPERAND(out, Rm, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + concat(&DECODE_STR(out), ", %s.4s", Rm_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleCryptographicTwoRegisterSHAInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 22, 23); + U32 opcode = bits(i->opcode, 12, 16); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(size != 0) + return 1; + + ADD_FIELD(out, size); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + { "sha1h", AD_INSTR_SHA1H }, { "sha1su1", AD_INSTR_SHA1SU1 }, + { "sha256su0", AD_INSTR_SHA256SU0 } + }; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + S32 instr_id = tab[opcode].instr_id; + + concat(&DECODE_STR(out), "%s", instr_s); + + if(instr_id == AD_INSTR_SHA1H){ + const char *Rd_s = GET_FP_REG(AD_RTBL_FP_32, Rd); + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_32, Rn); + + ADD_REG_OPERAND(out, Rd, _SZ(_32_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_32)); + ADD_REG_OPERAND(out, Rn, _SZ(_32_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_32)); + + concat(&DECODE_STR(out), " %s, %s", Rd_s, Rn_s); + } + else{ + const char *Rd_s = GET_FP_REG(AD_RTBL_FP_V_128, Rd); + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_V_128, Rn); + + ADD_REG_OPERAND(out, Rd, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_V_128)); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_V_128)); + + concat(&DECODE_STR(out), " %s.4s, %s.4s", Rd_s, Rn_s); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDCopyInstr(struct instruction *i, + struct ad_insn *out, S32 scalar){ + U32 Q = bits(i->opcode, 30, 30); + U32 op = bits(i->opcode, 29, 29); + U32 imm5 = bits(i->opcode, 16, 20); + U32 imm4 = bits(i->opcode, 11, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if((imm5 & ~0x10) == 0) + return 1; + + if(!scalar) + ADD_FIELD(out, Q); + + ADD_FIELD(out, op); + ADD_FIELD(out, imm5); + ADD_FIELD(out, imm4); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + S32 unaliased_instr_id = AD_NONE; + + S32 size = LowestSetBit(imm5, 5); + + if(op == 0 && (imm4 == 0 || imm4 == 1)){ + /* MOV alias for scalar DUP is always preferred */ + instr_s = scalar ? "mov" : "dup"; + instr_id = scalar ? AD_INSTR_MOV : AD_INSTR_DUP; + + unaliased_instr_id = AD_INSTR_DUP; + } + else if(op == 0 && imm4 == 5){ + instr_s = "smov"; + instr_id = AD_INSTR_SMOV; + + unaliased_instr_id = AD_INSTR_SMOV; + } + else if(op == 0 && imm4 == 7){ + S32 umov_alias = (size == 3 || size == 2); + + instr_s = umov_alias ? "mov" : "umov"; + instr_id = umov_alias ? AD_INSTR_MOV : AD_INSTR_UMOV; + + unaliased_instr_id = AD_INSTR_UMOV; + } + else if(Q == 1 && ((op == 0 && imm4 == 3) || op == 1)){ + /* MOV alias for INS (general) and INS (element) is always preferred */ + instr_s = "mov"; + instr_id = AD_INSTR_MOV; + + unaliased_instr_id = AD_INSTR_INS; + } + + if(!instr_s) + return 1; + + const char **Rd_Rtbl = NULL; + const char **Rn_Rtbl = NULL; + + U32 Rd_sz = 0; + U32 Rn_sz = 0; + + const char *T = NULL; + const char *Ts = NULL; + + const char **rtbls[] = { + AD_RTBL_FP_8, AD_RTBL_FP_16, AD_RTBL_FP_32, AD_RTBL_FP_64 + }; + + U32 sizes[] = { + _8_BIT, _16_BIT, _32_BIT, _64_BIT + }; + + const char *sizes_s[] = { + "b", "h", "s", "d" + }; + + if(unaliased_instr_id == AD_INSTR_DUP){ + if(scalar){ + if(size == -1 || size > 3) + return 1; + + Rd_Rtbl = rtbls[size]; + Rd_sz = sizes[size]; + + T = sizes_s[size]; + } + else{ + Rd_Rtbl = AD_RTBL_FP_V_128; + Rd_sz = _128_BIT; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!T) + return 1; + } + + if(imm4 == 0){ + /* DUP (element) */ + Rn_Rtbl = AD_RTBL_FP_V_128; + Rn_sz = _128_BIT; + + Ts = sizes_s[size]; + } + else{ + /* DUP (general) */ + if(size == -1 || size > 3) + return 1; + + Rn_Rtbl = size <= 2 ? AD_RTBL_GEN_32 : AD_RTBL_GEN_64; + Rn_sz = size <= 2 ? _32_BIT : _64_BIT; + } + } + else if(unaliased_instr_id == AD_INSTR_SMOV || unaliased_instr_id == AD_INSTR_UMOV){ + Rd_Rtbl = Q == 0 ? AD_RTBL_GEN_32 : AD_RTBL_GEN_64; + Rn_Rtbl = AD_RTBL_FP_V_128; + + Rd_sz = Q == 0 ? _32_BIT : _64_BIT; + Rn_sz = _128_BIT; + + if(unaliased_instr_id == AD_INSTR_SMOV){ + if((Q == 0 && size > 1) || (Q == 1 && size > 2)) + return 1; + } + else{ + if((Q == 0 && size > 2) || (Q == 1 && size != 3)) + return 1; + } + + Ts = sizes_s[size]; + } + else{ + Rd_Rtbl = AD_RTBL_FP_V_128; + Rd_sz = _128_BIT; + + if(op == 1){ + /* INS (element) */ + Rn_Rtbl = AD_RTBL_FP_V_128; + Rn_sz = _128_BIT; + } + else{ + /* INS (general) */ + if(size == -1 || size > 3) + return 1; + + Rn_Rtbl = size <= 2 ? AD_RTBL_GEN_32 : AD_RTBL_GEN_64; + Rn_sz = size <= 2 ? _32_BIT : _64_BIT; + } + + Ts = sizes_s[size]; + } + + if(!Rd_Rtbl || !Rn_Rtbl) + return 1; + + const char *Rd_s = NULL; + S32 Rd_prefer_zr = 0; + + if(unaliased_instr_id != AD_INSTR_SMOV && unaliased_instr_id != AD_INSTR_UMOV) + Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + else{ + Rd_s = GET_GEN_REG(Rd_Rtbl, Rd, PREFER_ZR); + Rd_prefer_zr = 1; + } + + const char *Rn_s = NULL; + S32 Rn_prefer_zr = 0; + + U32 index = (imm5 >> (size + 1)); + U32 index2 = (imm4 >> size); + + /* DUP (general) or INS (general) */ + if((unaliased_instr_id == AD_INSTR_DUP && imm4 == 1) || + (unaliased_instr_id == AD_INSTR_INS && op == 0)){ + Rn_s = GET_GEN_REG(Rn_Rtbl, Rn, PREFER_ZR); + Rn_prefer_zr = 1; + } + else{ + Rn_s = GET_FP_REG(Rn_Rtbl, Rn); + } + + ADD_REG_OPERAND(out, Rd, Rd_sz, Rd_prefer_zr, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, Rn_sz, Rn_prefer_zr, _SYSREG(AD_NONE), Rn_Rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + /* DUP (element, vector) or DUP (general) */ + if(unaliased_instr_id == AD_INSTR_DUP && !scalar) + concat(&DECODE_STR(out), ".%s", T); + /* INS (element) or INS (general) */ + else if(unaliased_instr_id == AD_INSTR_INS){ + /* index == index1 for INS (element) */ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&index); + concat(&DECODE_STR(out), ".%s[%d]", Ts, index); + } + + concat(&DECODE_STR(out), ", %s", Rn_s); + + /* DUP (general) or INS (general) */ + if((unaliased_instr_id == AD_INSTR_DUP && imm4 == 1) || + (unaliased_instr_id == AD_INSTR_INS && op == 0)){ + /* in this case, we're done constructing the decode string */ + SET_INSTR_ID(out, instr_id); + + return 0; + } + + /* DUP (element, scalar) */ + if(unaliased_instr_id == AD_INSTR_DUP && scalar) + concat(&DECODE_STR(out), ".%s", T); + else + concat(&DECODE_STR(out), ".%s", Ts); + + /* INS (element) */ + if(unaliased_instr_id == AD_INSTR_INS && op == 1){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&index2); + concat(&DECODE_STR(out), "[%d]", index2); + } + else{ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&index); + concat(&DECODE_STR(out), "[%d]", index); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +/* This function takes care of: + * - Advanced SIMD scalar three same FP16 + * - Advanced SIMD scalar three same extra + * - Advanced SIMD scalar three same + * - Advanced SIMD three same (FP16) + * - Advanced SIMD three same extra + * - Advanced SIMD three same + */ +static S32 DisassembleAdvancedSIMDThreeSameInstr(struct instruction *i, + struct ad_insn *out, S32 scalar, S32 fp16, S32 extra){ + U32 Q = bits(i->opcode, 30, 30); + U32 U = bits(i->opcode, 29, 29); + U32 a = bits(i->opcode, 23, 23); + U32 size = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + + U32 opcode = 0; + + if(fp16) + opcode = bits(i->opcode, 11, 13); + else if(extra) + opcode = bits(i->opcode, 11, 14); + else + opcode = bits(i->opcode, 11, 15); + + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(!scalar) + ADD_FIELD(out, Q); + + ADD_FIELD(out, U); + + if(fp16) + ADD_FIELD(out, a); + else + ADD_FIELD(out, size); + + ADD_FIELD(out, Rm); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + /* not a part of all instrs, don't include in field array */ + U32 rot = bits(i->opcode, 11, 12); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(fp16){ + const char **rtbl = AD_RTBL_FP_V_128; + U32 sz = _128_BIT; + + if(scalar){ + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + U32 idx = (U << 4) | (a << 3) | opcode; + + if(scalar){ + struct itab tab[] = { + /* three blanks, idxes [0-2] */ + { NULL, AD_NONE }, { NULL, AD_NONE }, { NULL, AD_NONE }, + { "fmulx", AD_INSTR_FMULX }, { "fcmeq", AD_INSTR_FCMEQ }, + /* two blanks, idxes [5-6] */ + { NULL, AD_NONE }, { NULL, AD_NONE }, + { "frecps", AD_INSTR_FRECPS }, + /* seven blanks, idxes [8-14] */ + { NULL, AD_NONE }, { NULL, AD_NONE }, { NULL, AD_NONE }, + { NULL, AD_NONE }, { NULL, AD_NONE }, { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "frsqrts", AD_INSTR_FRSQRTS }, + /* four blanks, idxes [16-19] */ + { NULL, AD_NONE }, { NULL, AD_NONE }, { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "fcmge", AD_INSTR_FCMGE }, { "facge", AD_INSTR_FACGE }, + /* four blanks, idxes [22-25] */ + { NULL, AD_NONE }, { NULL, AD_NONE }, { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "fabd", AD_INSTR_FABD }, + /* one blank, idx 27 */ + { NULL, AD_NONE }, + { "fcmgt", AD_INSTR_FCMGT }, { "facgt", AD_INSTR_FACGT } + }; + + if(OOB(idx, tab)) + return 1; + + instr_s = tab[idx].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[idx].instr_id; + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + } + else{ + struct itab tab[] = { + { "fmaxnm", AD_INSTR_FMAXNM }, { "fmla", AD_INSTR_FMLA }, + { "fadd", AD_INSTR_FADD }, { "fmulx", AD_INSTR_FMULX }, + { "fcmeq", AD_INSTR_FCMEQ }, + /* one blank, idx 5 */ + { NULL, AD_NONE }, + { "fmax", AD_INSTR_FMAX }, { "frecps", AD_INSTR_FRECPS }, + { "fminnm", AD_INSTR_FMINNM }, { "fmls", AD_INSTR_FMLS }, + { "fsub", AD_INSTR_FSUB }, + /* three blanks, idxes [11-13] */ + { NULL, AD_NONE }, { NULL, AD_NONE }, { NULL, AD_NONE }, + { "fmin", AD_INSTR_FMIN }, { "frsqrts", AD_INSTR_FRSQRTS }, + { "fmaxnmp", AD_INSTR_FMAXNMP }, + /* one blank, idx 17 */ + { NULL, AD_NONE }, + { "faddp", AD_INSTR_FADDP }, { "fmul", AD_INSTR_FMUL }, + { "fcmge", AD_INSTR_FCMGE }, { "facge", AD_INSTR_FACGE }, + { "fmaxp", AD_INSTR_FMAXP }, { "fdiv", AD_INSTR_FDIV }, + { "fminnmp", AD_INSTR_FMINNMP }, + /* one blank, idx 25 */ + { NULL, AD_NONE }, + { "fabd", AD_INSTR_FABD }, + /* one blank, idx 27 */ + { NULL, AD_NONE }, + { "fcmgt", AD_INSTR_FCMGT }, { "fminp", AD_INSTR_FMINP } + }; + + if(OOB(idx, tab)) + return 1; + + instr_s = tab[idx].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[idx].instr_id; + + const char *arrangement = Q == 0 ? "4h" : "8h"; + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s", instr_s, Rd_s, + arrangement, Rn_s, arrangement, Rm_s, arrangement); + } + } + else if(extra){ + if(scalar){ + if(U != 1) + return 1; + + if(size == 0 || size == 3) + return 1; + + instr_s = opcode == 0 ? "sqrdmlah" : "sqrdmlsh"; + instr_id = opcode == 0 ? AD_INSTR_SQRDMLAH : AD_INSTR_SQRDMLSH; + + const char **rtbl = AD_RTBL_FP_16; + U32 sz = _16_BIT; + + if(size == 2){ + rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + } + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + } + else{ + const char **rtbl = AD_RTBL_FP_V_128; + U32 sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + if(opcode == 2){ + instr_s = U == 0 ? "sdot" : "udot"; + instr_id = U == 0 ? AD_INSTR_SDOT : AD_INSTR_UDOT; + + const char *Ta = Q == 0 ? "2s" : "4s"; + const char *Tb = Q == 0 ? "8b" : "16b"; + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s", instr_s, + Rd_s, Ta, Rn_s, Tb, Rm_s, Tb); + } + else{ + if(opcode < 2){ + instr_s = opcode == 0 ? "sqrdmlah" : "sqrdmlsh"; + instr_id = opcode == 0 ? AD_INSTR_SQRDMLAH : AD_INSTR_SQRDMLSH; + } + else{ + if((opcode & ~3) == 8){ + instr_s = "fcmla"; + instr_id = AD_INSTR_FCMLA; + } + else if((opcode & ~2) == 12){ + instr_s = "fcadd"; + instr_id = AD_INSTR_FCADD; + } + else{ + return 1; + } + } + + const char *arrangement = NULL; + + if(size == 1) + arrangement = Q == 0 ? "4h" : "8h"; + else if(size == 2) + arrangement = Q == 0 ? "2s" : "4s"; + else if((instr_id == AD_INSTR_FCMLA || instr_id == AD_INSTR_FCADD) && + size == 3 && Q == 1){ + arrangement = "2d"; + } + + if(!arrangement) + return 1; + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s", instr_s, + Rd_s, arrangement, Rn_s, arrangement, Rm_s, arrangement); + + if(instr_id == AD_INSTR_FCMLA || instr_id == AD_INSTR_FCADD){ + U32 rotate = 0; + + if(instr_id == AD_INSTR_FCMLA) + rotate = rot * 90; + else + rotate = rot == 0 ? 90 : 270; + + concat(&DECODE_STR(out), ", #%d", rotate); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&rotate); + } + } + } + } + else{ + const char **rtbls[] = { + AD_RTBL_FP_8, AD_RTBL_FP_16, AD_RTBL_FP_32, AD_RTBL_FP_64 + }; + + U32 sizes[] = { + _8_BIT, _16_BIT, _32_BIT, _64_BIT + }; + + const char **rtbl = NULL; + const char *T = NULL; + + U32 sz = 0; + + if(opcode == 0){ + if(scalar) + return 1; + + instr_s = "shadd"; + instr_id = AD_INSTR_SHADD; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 1){ + instr_s = U == 0 ? "sqadd" : "uqadd"; + instr_id = U == 0 ? AD_INSTR_SQADD : AD_INSTR_UQADD; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 2){ + if(scalar) + return 1; + + instr_s = U == 0 ? "srhadd" : "urhadd"; + instr_id = U == 0 ? AD_INSTR_SRHADD : AD_INSTR_URHADD; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 3){ + if(scalar) + return 1; + + struct itab u0[] = { + { "and", AD_INSTR_AND }, { "bic", AD_INSTR_BIC }, + { "orr", AD_INSTR_ORR }, { "orn", AD_INSTR_ORN } + }; + + struct itab u1[] = { + { "eor", AD_INSTR_EOR }, { "bsl", AD_INSTR_BSL }, + { "bit", AD_INSTR_BIT }, { "bif", AD_INSTR_BIF } + }; + + /* both table sizes are the same, don't need to check u1 */ + if(OOB(size, u0)) + return 1; + + instr_s = U == 0 ? u0[size].instr_s : u1[size].instr_s; + instr_id = U == 0 ? u0[size].instr_id : u1[size].instr_id; + + T = Q == 0 ? "8b" : "16b"; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 4){ + if(scalar) + return 1; + + instr_s = U == 0 ? "shsub" : "uhsub"; + instr_id = U == 0 ? AD_INSTR_SHSUB : AD_INSTR_UHSUB; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 5){ + instr_s = U == 0 ? "sqsub" : "uqsub"; + instr_id = U == 0 ? AD_INSTR_SQSUB : AD_INSTR_UQSUB; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 6){ + if(scalar && size != 3) + return 1; + + instr_s = U == 0 ? "cmgt" : "cmhi"; + instr_id = U == 0 ? AD_INSTR_CMGT : AD_INSTR_CMHI; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 7){ + if(scalar && size != 3) + return 1; + + instr_s = U == 0 ? "cmge" : "cmhs"; + instr_id = U == 0 ? AD_INSTR_CMGE : AD_INSTR_CMHS; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 8){ + if(scalar && size != 3) + return 1; + + instr_s = U == 0 ? "sshl" : "ushl"; + instr_id = U == 0 ? AD_INSTR_SSHL : AD_INSTR_USHL; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 9){ + instr_s = U == 0 ? "sqshl" : "uqshl"; + instr_id = U == 0 ? AD_INSTR_SQSHL : AD_INSTR_UQSHL; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0xa){ + if(scalar && size != 3) + return 1; + + instr_s = U == 0 ? "srshl" : "urshl"; + instr_id = U == 0 ? AD_INSTR_SRSHL : AD_INSTR_URSHL; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0xb){ + instr_s = U == 0 ? "sqrshl" : "uqrshl"; + instr_id = U == 0 ? AD_INSTR_SQRSHL : AD_INSTR_UQRSHL; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0xc){ + if(scalar) + return 1; + + instr_s = U == 0 ? "smax" : "umax"; + instr_id = U == 0 ? AD_INSTR_SMAX : AD_INSTR_UMAX; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0xd){ + if(scalar) + return 1; + + instr_s = U == 0 ? "smin" : "umin"; + instr_id = U == 0 ? AD_INSTR_SMIN : AD_INSTR_UMIN; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0xe){ + if(scalar) + return 1; + + instr_s = U == 0 ? "sabd" : "uabd"; + instr_id = U == 0 ? AD_INSTR_SABD : AD_INSTR_UABD; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0xf){ + if(scalar) + return 1; + + instr_s = U == 0 ? "saba" : "uaba"; + instr_id = U == 0 ? AD_INSTR_SABA : AD_INSTR_UABA; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x10){ + if(scalar && size != 3) + return 1; + + instr_s = U == 0 ? "add" : "sub"; + instr_id = U == 0 ? AD_INSTR_ADD : AD_INSTR_SUB; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0x11){ + if(scalar && size != 3) + return 1; + + instr_s = U == 0 ? "cmtst" : "cmeq"; + instr_id = U == 0 ? AD_INSTR_CMTST : AD_INSTR_CMEQ; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0x12){ + if(scalar) + return 1; + + instr_s = U == 0 ? "mla" : "mls"; + instr_id = U == 0 ? AD_INSTR_MLA : AD_INSTR_MLS; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x13){ + if(scalar) + return 1; + + instr_s = U == 0 ? "mul" : "pmul"; + instr_id = U == 0 ? AD_INSTR_MUL : AD_INSTR_PMUL; + + if(instr_id == AD_INSTR_PMUL) + T = Q == 0 ? "8b" : "16b"; + else{ + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + } + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x14){ + if(scalar) + return 1; + + instr_s = U == 0 ? "smaxp" : "umaxp"; + instr_id = U == 0 ? AD_INSTR_SMAXP : AD_INSTR_UMAXP; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x15){ + if(scalar) + return 1; + + instr_s = U == 0 ? "sminp" : "uminp"; + instr_id = U == 0 ? AD_INSTR_SMINP : AD_INSTR_UMINP; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x16){ + if(scalar && (size == 0 || size == 3)) + return 1; + + instr_s = U == 0 ? "sqdmulh" : "sqrdmulh"; + instr_id = U == 0 ? AD_INSTR_SQDMULH : AD_INSTR_SQRDMULH; + + if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0x17){ + if(scalar) + return 1; + + if(U == 1) + return 1; + + instr_s = "addp"; + instr_id = AD_INSTR_ADDP; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x18){ + if(scalar) + return 1; + + U32 s = size >> 1; + + if(U == 0){ + instr_s = s == 0 ? "fmaxnm" : "fminnm"; + instr_id = s == 0 ? AD_INSTR_FMAXNM : AD_INSTR_FMINNM; + } + else{ + instr_s = s == 0 ? "fmaxnmp" : "fminnmp"; + instr_id = s == 0 ? AD_INSTR_FMAXNMP : AD_INSTR_FMINNMP; + } + + U32 _sz = (size & 1); + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x19){ + if(scalar) + return 1; + + U32 s = size >> 1; + + if(U == 0){ + instr_s = s == 0 ? "fmla" : "fmls"; + instr_id = s == 0 ? AD_INSTR_FMLA : AD_INSTR_FMLS; + } + else{ + if(size == 1 || size == 3) + return 1; + + instr_s = size == 0 ? "fmlal2" : "fmlsl2"; + instr_id = size == 0 ? AD_INSTR_FMLAL2 : AD_INSTR_FMLSL2; + + const char *Ta = Q == 0 ? "2s" : "4s"; + const char *Tb = Q == 0 ? "2h" : "4h"; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s", instr_s, Rd_s, + Ta, Rn_s, Tb, Rm_s, Tb); + + SET_INSTR_ID(out, instr_id); + + return 0; + } + + U32 _sz = (size & 1); + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x1a){ + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(scalar){ + if(U != 1 && s != 1) + return 1; + + instr_s = "fabd"; + instr_id = AD_INSTR_FABD; + + rtbl = rtbls[2 + _sz]; + sz = sizes[2 + _sz]; + } + else{ + if(U == 0){ + instr_s = s == 0 ? "fadd" : "fsub"; + instr_id = s == 0 ? AD_INSTR_FADD : AD_INSTR_FSUB; + } + else{ + instr_s = s == 0 ? "faddp" : "fabd"; + instr_id = s == 0 ? AD_INSTR_FADDP : AD_INSTR_FABD; + } + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0x1b){ + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(scalar){ + if(s == 1) + return 1; + + if(U == 1 && s == 0) + return 1; + + instr_s = "fmulx"; + instr_id = AD_INSTR_FMULX; + + rtbl = rtbls[2 + _sz]; + sz = sizes[2 + _sz]; + } + else{ + if(s == 1) + return 1; + + instr_s = U == 0 ? "fmulx" : "fmul"; + instr_id = U == 0 ? AD_INSTR_FMULX : AD_INSTR_FMUL; + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 0x1c){ + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(U == 0 && s == 1) + return 1; + + if(U == 0){ + instr_s = "fcmeq"; + instr_id = AD_INSTR_FCMEQ; + } + else{ + instr_s = s == 0 ? "fcmge" : "fcmgt"; + instr_id = s == 0 ? AD_INSTR_FCMGE : AD_INSTR_FCMGT; + } + + if(scalar){ + rtbl = rtbls[2 + _sz]; + sz = sizes[2 + _sz]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + } + else if(opcode == 0x1d){ + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(scalar && U == 0) + return 1; + + if(U == 1){ + instr_s = s == 0 ? "facge" : "facgt"; + instr_id = s == 0 ? AD_INSTR_FACGE : AD_INSTR_FACGT; + } + else{ + if(size == 1 || size == 3) + return 1; + + instr_s = size == 0 ? "fmlal" : "fmlsl"; + instr_id = size == 0 ? AD_INSTR_FMLAL : AD_INSTR_FMLSL; + + const char *Ta = Q == 0 ? "2s" : "4s"; + const char *Tb = Q == 0 ? "2h" : "4h"; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s", instr_s, Rd_s, + Ta, Rn_s, Tb, Rm_s, Tb); + + SET_INSTR_ID(out, instr_id); + + return 0; + } + + if(scalar){ + rtbl = rtbls[2 + _sz]; + sz = sizes[2 + _sz]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + } + else if(opcode == 0x1e){ + if(scalar) + return 1; + + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(U == 0){ + instr_s = s == 0 ? "fmax" : "fmin"; + instr_id = s == 0 ? AD_INSTR_FMAX : AD_INSTR_FMIN; + } + else{ + instr_s = s == 0 ? "fmaxp" : "fminp"; + instr_id = s == 0 ? AD_INSTR_FMAXP : AD_INSTR_FMINP; + } + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x1f){ + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(scalar && U != 0) + return 1; + + if(U == 0){ + instr_s = s == 0 ? "frecps" : "frsqrts"; + instr_id = s == 0 ? AD_INSTR_FRECPS : AD_INSTR_FRSQRTS; + } + else{ + if(s == 1) + return 1; + + instr_s = "fdiv"; + instr_id = AD_INSTR_FDIV; + } + + if(scalar){ + rtbl = rtbls[2 + _sz]; + sz = sizes[2 + _sz]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + } + + if(!rtbl || !instr_s) + return 1; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(scalar) + concat(&DECODE_STR(out), ", %s, %s", Rn_s, Rm_s); + else + concat(&DECODE_STR(out), ".%s, %s.%s, %s.%s", T, Rn_s, T, Rm_s, T); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +/* This function takes care of: + * - Advanced SIMD scalar two-register miscellaneous FP16 + * - Advanced SIMD scalar two-register miscellaneous + * - Advanced SIMD two-register miscellaneous (FP16) + * - Advanced SIMD two-register miscellaneous + */ +static S32 DisassembleAdvancedSIMDTwoRegisterMiscellaneousInstr(struct instruction *i, + struct ad_insn *out, S32 scalar, S32 fp16){ + U32 Q = bits(i->opcode, 30, 30); + U32 U = bits(i->opcode, 29, 29); + U32 a = bits(i->opcode, 23, 23); + U32 size = bits(i->opcode, 22, 23); + U32 opcode = bits(i->opcode, 12, 16); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(!scalar) + ADD_FIELD(out, Q); + + ADD_FIELD(out, U); + + if(fp16) + ADD_FIELD(out, a); + else + ADD_FIELD(out, size); + + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + const char **rtbls[] = { + AD_RTBL_FP_8, AD_RTBL_FP_16, AD_RTBL_FP_32, AD_RTBL_FP_64 + }; + + U32 sizes[] = { + _8_BIT, _16_BIT, _32_BIT, _64_BIT + }; + + const char **rtbl = NULL; + const char *T = NULL; + + U32 sz = 0; + + S32 add_zero = 0; + S32 add_zerof = 0; + + if(opcode < 2){ + if(scalar || fp16) + return 1; + + if(opcode == 1 && U == 1) + return 1; + + U32 o0 = bits(i->opcode, 12, 12); + U32 op = (o0 << 1) | U; + + struct itab tab[] = { + { "rev64", AD_INSTR_REV64 }, { "rev32", AD_INSTR_REV32 }, + { "rev16", AD_INSTR_REV16 } + }; + + if(OOB(op, tab)) + return 1; + + instr_s = tab[op].instr_s; + instr_id = tab[op].instr_id; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 2 || opcode == 6){ + if(scalar || fp16) + return 1; + + if(opcode == 2){ + instr_s = U == 0 ? "saddlp" : "uaddlp"; + instr_id = U == 0 ? AD_INSTR_SADDLP : AD_INSTR_UADDLP; + } + else{ + instr_s = U == 0 ? "sadalp" : "uadalp"; + instr_id = U == 0 ? AD_INSTR_SADALP : AD_INSTR_UADALP; + } + + const char *Ta = NULL; + const char *Tb = NULL; + + if(size == 0){ + Ta = Q == 0 ? "4h" : "8h"; + Tb = Q == 0 ? "8b" : "16b"; + } + else if(size == 1){ + Ta = Q == 0 ? "2s" : "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else if(size == 2){ + Ta = Q == 0 ? "1d" : "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + + if(!Ta || !Tb) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s", instr_s, Rd_s, Ta, Rn_s, Tb); + + SET_INSTR_ID(out, instr_id); + + return 0; + } + else if(opcode == 3 || opcode == 7){ + if(fp16) + return 1; + + if(opcode == 3){ + instr_s = U == 0 ? "suqadd" : "usqadd"; + instr_id = U == 0 ? AD_INSTR_SUQADD : AD_INSTR_USQADD; + } + else{ + instr_s = U == 0 ? "sqabs" : "sqneg"; + instr_id = U == 0 ? AD_INSTR_SQABS : AD_INSTR_SQNEG; + } + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode == 4){ + if(scalar || fp16) + return 1; + + instr_s = U == 0 ? "cls" : "clz"; + instr_id = U == 0 ? AD_INSTR_CLS : AD_INSTR_CLZ; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 5){ + if(scalar || fp16) + return 1; + + if(U == 0){ + if(size != 0) + return 1; + + instr_s = "cnt"; + instr_id = AD_INSTR_CNT; + } + else{ + if((size >> 1) == 1) + return 1; + + instr_s = size == 0 ? "not" : "rbit"; + instr_id = size == 0 ? AD_INSTR_NOT : AD_INSTR_RBIT; + } + + T = Q == 0 ? "8b" : "16b"; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode >= 8 && opcode <= 0xa){ + if(fp16) + return 1; + + if(opcode == 0xa && U == 1) + return 1; + + if(scalar && size != 3) + return 1; + + U32 op = bits(i->opcode, 12, 12); + U32 cop = (op << 1) | U; + + struct itab tab[] = { + { "cmgt", AD_INSTR_CMGT }, { "cmge", AD_INSTR_CMGE }, + { "cmeq", AD_INSTR_CMEQ }, { "cmle", AD_INSTR_CMLE } + }; + + instr_s = tab[cop].instr_s; + instr_id = tab[cop].instr_id; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + + add_zero = 1; + } + else if(opcode == 0xb){ + if(fp16) + return 1; + + if(scalar && size != 3) + return 1; + + instr_s = U == 0 ? "abs" : "neg"; + instr_id = U == 0 ? AD_INSTR_ABS : AD_INSTR_NEG; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!scalar && !T) + return 1; + + if(scalar){ + rtbl = rtbls[size]; + sz = sizes[size]; + } + else{ + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + else if(opcode >= 0xc && opcode <= 0xe){ + if(opcode == 0xe && U == 1) + return 1; + + U32 _sz = (size & 1); + + U32 op = bits(i->opcode, 12, 12); + U32 cop = (op << 1) | U; + + struct itab tab[] = { + { "fcmgt", AD_INSTR_FCMGT }, { "fcmge", AD_INSTR_FCMGE }, + { "fcmeq", AD_INSTR_FCMEQ }, { "fcmle", AD_INSTR_FCMLE } + }; + + instr_s = tab[cop].instr_s; + instr_id = tab[cop].instr_id; + + if(scalar && fp16){ + T = Q == 0 ? "4h" : "8h"; + + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + else if(scalar){ + rtbl = rtbls[2 + _sz]; + sz = sizes[2 + _sz]; + } + else if(fp16){ + T = Q == 0 ? "4h" : "8h"; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else{ + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + + add_zerof = 1; + } + else if(opcode == 0xf){ + if(scalar) + return 1; + + instr_s = U == 0 ? "fabs" : "fneg"; + instr_id = U == 0 ? AD_INSTR_FABS : AD_INSTR_FNEG; + + U32 _sz = (size & 1); + + if(fp16) + T = Q == 0 ? "4h" : "8h"; + else{ + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + } + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode == 0x12 || opcode == 0x14){ + if(fp16) + return 1; + + if(scalar && size == 3) + return 1; + + if(U == 0){ + if(opcode == 0x12){ + instr_s = Q == 0 ? "xtn" : "xtn2"; + instr_id = Q == 0 ? AD_INSTR_XTN : AD_INSTR_XTN2; + } + else{ + if(scalar){ + instr_s = "sqxtn"; + instr_id = AD_INSTR_SQXTN; + } + else{ + instr_s = Q == 0 ? "sqxtn" : "sqxtn2"; + instr_id = Q == 0 ? AD_INSTR_SQXTN : AD_INSTR_SQXTN2; + } + } + } + else{ + if(opcode == 0x12){ + if(scalar){ + instr_s = "sqxtun"; + instr_id = AD_INSTR_SQXTUN; + } + else{ + instr_s = Q == 0 ? "sqxtun" : "sqxtun2"; + instr_id = Q == 0 ? AD_INSTR_SQXTUN : AD_INSTR_SQXTUN2; + } + } + else{ + if(scalar){ + instr_s = "uqxtn"; + instr_id = AD_INSTR_UQXTN; + } + else{ + instr_s = Q == 0 ? "uqxtn" : "uqxtn2"; + instr_id = Q == 0 ? AD_INSTR_UQXTN : AD_INSTR_UQXTN2; + } + } + } + + concat(&DECODE_STR(out), "%s", instr_s); + + if(scalar){ + const char **Rd_rtbl = rtbls[size]; + const char **Rn_rtbl = rtbls[1 + size]; + + U32 Rd_sz = sizes[size]; + U32 Rn_sz = sizes[1 + size]; + + const char *Rd_s = GET_FP_REG(Rd_rtbl, Rd); + const char *Rn_s = GET_FP_REG(Rn_rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_rtbl); + ADD_REG_OPERAND(out, Rn, Rn_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_rtbl); + + concat(&DECODE_STR(out), " %s, %s", Rd_s, Rn_s); + } + else{ + const char *Ta = NULL; + const char *Tb = NULL; + + if(size == 0){ + Ta = "8h"; + Tb = Q == 0 ? "8b" : "16b"; + } + else if(size == 1){ + Ta = "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else if(size == 2){ + Ta = "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + + if(!Ta || !Tb) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), " %s.%s, %s.%s", Rd_s, Tb, Rn_s, Ta); + } + + SET_INSTR_ID(out, instr_id); + + return 0; + } + else if(opcode == 0x13){ + if(fp16 || scalar) + return 1; + + if(U == 0) + return 1; + + instr_s = Q == 0 ? "shll" : "shll2"; + instr_id = Q == 0 ? AD_INSTR_SHLL : AD_INSTR_SHLL2; + + const char *Ta = NULL; + const char *Tb = NULL; + + if(size == 0){ + Ta = "8h"; + Tb = Q == 0 ? "8b" : "16b"; + } + else if(size == 1){ + Ta = "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else if(size == 2){ + Ta = "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + + if(!Ta || !Tb) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + U32 shift = 8 << size; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&shift); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, #%#x", instr_s, Rd_s, Ta, + Rn_s, Tb, shift); + + SET_INSTR_ID(out, instr_id); + + return 0; + } + else if(opcode == 0x16){ + if(fp16) + return 1; + + U32 _sz = (size & 1); + + if(U == 0){ + instr_s = Q == 0 ? "fcvtn" : "fcvtn2"; + instr_id = Q == 0 ? AD_INSTR_FCVTN : AD_INSTR_FCVTN2; + } + else{ + if(scalar){ + instr_s = "fcvtxn"; + instr_id = AD_INSTR_FCVTXN; + } + else{ + instr_s = Q == 0 ? "fcvtxn" : "fcvtxn2"; + instr_id = Q == 0 ? AD_INSTR_FCVTXN : AD_INSTR_FCVTXN2; + } + } + + concat(&DECODE_STR(out), "%s", instr_s); + + if(scalar){ + if(_sz == 0) + return 1; + + const char **Rd_rtbl = AD_RTBL_FP_32; + const char **Rn_rtbl = AD_RTBL_FP_64; + + U32 Rd_sz = _32_BIT; + U32 Rn_sz = _64_BIT; + + const char *Rd_s = GET_FP_REG(Rd_rtbl, Rd); + const char *Rn_s = GET_FP_REG(Rn_rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_rtbl); + ADD_REG_OPERAND(out, Rn, Rn_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_rtbl); + + concat(&DECODE_STR(out), " %s, %s", Rd_s, Rn_s); + } + else{ + const char *Ta = NULL; + const char *Tb = NULL; + + if(_sz == 0){ + if(instr_id == AD_INSTR_FCVTXN || instr_id == AD_INSTR_FCVTXN2) + return 1; + + Ta = "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else if(_sz == 1){ + Ta = "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + + if(!Ta || !Tb) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), " %s.%s, %s.%s", Rd_s, Tb, Rn_s, Ta); + } + + SET_INSTR_ID(out, instr_id); + + return 0; + } + else if(opcode == 0x17){ + if(fp16 || scalar) + return 1; + + U32 _sz = (size & 1); + + instr_s = Q == 0 ? "fcvtl" : "fcvtl2"; + instr_id = Q == 0 ? AD_INSTR_FCVTL : AD_INSTR_FCVTL2; + + const char *Ta = NULL; + const char *Tb = NULL; + + if(_sz == 0){ + Ta = "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else if(_sz == 1){ + Ta = "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + + if(!Ta || !Tb) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s", instr_s, Rd_s, Ta, Rn_s, Tb); + + SET_INSTR_ID(out, instr_id); + + return 0; + } + else if(opcode == 0x18 || opcode == 0x19 || opcode == 0x1e || opcode == 0x1f){ + if(scalar) + return 1; + + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(U == 0){ + if(s == 0){ + if(opcode == 0x18){ + instr_s = "frintn"; + instr_id = AD_INSTR_FRINTN; + } + else if(opcode == 0x19){ + instr_s = "frintm"; + instr_id = AD_INSTR_FRINTM; + } + else if(opcode == 0x1e){ + instr_s = "frint32z"; + instr_id = AD_INSTR_FRINT32Z; + } + else{ + instr_s = "frint64z"; + instr_id = AD_INSTR_FRINT64Z; + } + } + else{ + if(opcode == 0x1e || opcode == 0x1f) + return 1; + + instr_s = opcode == 0x18 ? "frintp" : "frintz"; + instr_id = opcode == 0x18 ? AD_INSTR_FRINTP : AD_INSTR_FRINTZ; + } + } + else{ + if(s == 0){ + if(opcode == 0x18){ + instr_s = "frinta"; + instr_id = AD_INSTR_FRINTA; + } + else if(opcode == 0x19){ + instr_s = "frintx"; + instr_id = AD_INSTR_FRINTX; + } + else if(opcode == 0x1e){ + instr_s = "frint32x"; + instr_id = AD_INSTR_FRINT32X; + } + else{ + instr_s = "frint64x"; + instr_id = AD_INSTR_FRINT64X; + } + } + else{ + if(opcode == 0x18 || opcode == 0x1e) + return 1; + + instr_s = opcode == 0x19 ? "frinti" : "fsqrt"; + instr_id = opcode == 0x19 ? AD_INSTR_FRINTI : AD_INSTR_FSQRT; + } + } + + if(fp16) + T = Q == 0 ? "4h" : "8h"; + else{ + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + + if(!T) + return 1; + } + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else if(opcode >= 0x1a && opcode <= 0x1d){ + U32 s = size >> 1; + U32 tempop = opcode - 0x1a; + + if(U == 0){ + if(s == 0){ + struct itab tab[] = { + { "fcvtns", AD_INSTR_FCVTNS }, { "fcvtms", AD_INSTR_FCVTMS }, + { "fcvtas", AD_INSTR_FCVTAS }, { "scvtf", AD_INSTR_SCVTF } + }; + + if(OOB(tempop, tab)) + return 1; + + instr_s = tab[tempop].instr_s; + instr_id = tab[tempop].instr_id; + } + else{ + struct itab tab[] = { + { "fcvtps", AD_INSTR_FCVTPS }, { "fcvtzs", AD_INSTR_FCVTZS }, + { "urecpe", AD_INSTR_URECPE }, { "frecpe", AD_INSTR_FRECPE } + }; + + if(OOB(tempop, tab)) + return 1; + + instr_s = tab[tempop].instr_s; + instr_id = tab[tempop].instr_id; + } + } + else{ + if(s == 0){ + struct itab tab[] = { + { "fcvtnu", AD_INSTR_FCVTNU }, { "fcvtmu", AD_INSTR_FCVTMU }, + { "fcvtau", AD_INSTR_FCVTAU }, { "ucvtf", AD_INSTR_UCVTF } + }; + + if(OOB(tempop, tab)) + return 1; + + instr_s = tab[tempop].instr_s; + instr_id = tab[tempop].instr_id; + } + else{ + struct itab tab[] = { + { "fcvtpu", AD_INSTR_FCVTPU }, { "fcvtzu", AD_INSTR_FCVTZU }, + { "ursqrte", AD_INSTR_URSQRTE }, { "frsqrte", AD_INSTR_FRSQRTE } + }; + + if(OOB(tempop, tab)) + return 1; + + instr_s = tab[tempop].instr_s; + instr_id = tab[tempop].instr_id; + } + } + + U32 _sz = (size & 1); + + if(scalar && fp16){ + T = Q == 0 ? "4h" : "8h"; + + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + else if(scalar){ + rtbl = _sz == 0 ? AD_RTBL_FP_32 : AD_RTBL_FP_64; + sz = _sz == 0 ? _32_BIT : _64_BIT; + } + else if(fp16){ + T = Q == 0 ? "4h" : "8h"; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + else{ + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1){ + if(instr_id == AD_INSTR_URECPE || instr_id == AD_INSTR_URSQRTE) + return 1; + + T = "2d"; + } + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + } + + if(!rtbl) + return 1; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(scalar) + concat(&DECODE_STR(out), ", %s", Rn_s); + else + concat(&DECODE_STR(out), ".%s, %s.%s", T, Rn_s, T); + + if(add_zero){ + ADD_IMM_OPERAND(out, AD_IMM_INT, 0); + concat(&DECODE_STR(out), ", #0"); + } + else if(add_zerof){ + ADD_IMM_OPERAND(out, AD_IMM_FLOAT, 0); + concat(&DECODE_STR(out), ", #0.0"); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDScalarPairwiseInstr(struct instruction *i, + struct ad_insn *out){ + U32 U = bits(i->opcode, 29, 29); + U32 size = bits(i->opcode, 22, 23); + U32 opcode = bits(i->opcode, 12, 16); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, U); + ADD_FIELD(out, size); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char **Rd_rtbl = NULL; + const char *T = NULL; + + U32 Rd_sz = 0; + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(opcode == 0x1b){ + if(U == 1 && size != 3) + return 1; + + instr_s = "addp"; + instr_id = AD_INSTR_ADDP; + + Rd_rtbl = AD_RTBL_FP_64; + Rd_sz = _64_BIT; + + T = "2d"; + } + else{ + U32 s = size >> 1; + U32 _sz = (size & 1); + + if(opcode == 13 && s == 1) + return 1; + + S32 fp16 = (U == 0); + + U32 tempop = opcode - 12; + + struct itab tab[] = { + { s == 0 ? "fmaxnmp" : "fminnmp", s == 0 ? AD_INSTR_FMAXNMP : AD_INSTR_FMINNMP }, + { s == 0 ? "faddp" : NULL, s == 0 ? AD_INSTR_FADDP : AD_NONE }, + /* one blank, idx 2 */ + { NULL, AD_NONE }, + { s == 0 ? "fmaxp" : "fminp", s == 0 ? AD_INSTR_FMAXP : AD_INSTR_FMINP } + }; + + if(OOB(tempop, tab)) + return 1; + + instr_s = tab[tempop].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[tempop].instr_id; + + if(fp16 && _sz == 1) + return 1; + + if(fp16){ + Rd_rtbl = AD_RTBL_FP_16; + Rd_sz = _16_BIT; + + T = "2h"; + } + else{ + Rd_rtbl = _sz == 0 ? AD_RTBL_FP_32 : AD_RTBL_FP_64; + Rd_sz = _sz == 0 ? _32_BIT : _64_BIT; + + T = _sz == 0 ? "2s" : "2d"; + } + } + + if(!Rd_rtbl) + return 1; + + const char *Rd_s = GET_FP_REG(Rd_rtbl, Rd); + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_V_128, Rn); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_rtbl); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + concat(&DECODE_STR(out), "%s %s, %s.%s", instr_s, Rd_s, Rn_s, T); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDThreeDifferentInstr(struct instruction *i, + struct ad_insn *out, S32 scalar){ + U32 Q = bits(i->opcode, 30, 30); + U32 U = bits(i->opcode, 29, 29); + U32 size = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 12, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(!scalar) + ADD_FIELD(out, Q); + + ADD_FIELD(out, U); + ADD_FIELD(out, size); + ADD_FIELD(out, Rm); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + const char **Rd_Rtbl = NULL; + const char **Rn_Rm_Rtbl = NULL; + + U32 Rd_sz = 0; + U32 Rn_Rm_sz = 0; + + const char *first_T = NULL; + const char *second_T = NULL; + const char *third_T = NULL; + + if(scalar){ + if(U == 1) + return 1; + + if(size == 0 || size == 3) + return 1; + + U32 tempop = opcode - 9; + + struct itab tab[] = { + { "sqdmlal", AD_INSTR_SQDMLAL }, + /* one blank, idx 1 */ + { NULL, AD_NONE }, + { "sqdmlsl", AD_INSTR_SQDMLSL }, + /* one blank, idx 3 */ + { NULL, AD_NONE }, + { "sqdmull", AD_INSTR_SQDMULL } + }; + + if(OOB(tempop, tab)) + return 1; + + instr_s = tab[tempop].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[tempop].instr_id; + + Rd_Rtbl = size == 1 ? AD_RTBL_FP_32 : AD_RTBL_FP_64; + Rn_Rm_Rtbl = size == 1 ? AD_RTBL_FP_16 : AD_RTBL_FP_32; + + Rd_sz = size == 1 ? _32_BIT : _64_BIT; + Rn_Rm_sz = size == 1 ? _16_BIT : _32_BIT; + } + else{ + struct itab u0_tab[] = { + { Q == 0 ? "saddl" : "saddl2", Q == 0 ? AD_INSTR_SADDL : AD_INSTR_SADDL2 }, + { Q == 0 ? "saddw" : "saddw2", Q == 0 ? AD_INSTR_SADDW : AD_INSTR_SADDW2 }, + { Q == 0 ? "ssubl" : "ssubl2", Q == 0 ? AD_INSTR_SSUBL : AD_INSTR_SSUBL2 }, + { Q == 0 ? "ssubw" : "ssubw2", Q == 0 ? AD_INSTR_SSUBW : AD_INSTR_SSUBW2 }, + { Q == 0 ? "addhn" : "addhn2", Q == 0 ? AD_INSTR_ADDHN : AD_INSTR_ADDHN2 }, + { Q == 0 ? "sabal" : "sabal2", Q == 0 ? AD_INSTR_SABAL : AD_INSTR_SABAL2 }, + { Q == 0 ? "subhn" : "subhn2", Q == 0 ? AD_INSTR_SUBHN : AD_INSTR_SUBHN2 }, + { Q == 0 ? "sabdl" : "sabdl2", Q == 0 ? AD_INSTR_SABDL : AD_INSTR_SABDL2 }, + { Q == 0 ? "smlal" : "smlal2", Q == 0 ? AD_INSTR_SMLAL : AD_INSTR_SMLAL2 }, + { Q == 0 ? "sqdmlal" : "sqdmlal2", Q == 0 ? AD_INSTR_SQDMLAL : AD_INSTR_SQDMLAL2 }, + { Q == 0 ? "smlsl" : "smlsl2", Q == 0 ? AD_INSTR_SMLSL : AD_INSTR_SMLSL2 }, + { Q == 0 ? "sqdmlsl" : "sqdmlsl2", Q == 0 ? AD_INSTR_SQDMLSL : AD_INSTR_SQDMLSL2 }, + { Q == 0 ? "smull" : "smull2", Q == 0 ? AD_INSTR_SMULL : AD_INSTR_SMULL2 }, + { Q == 0 ? "sqdmull" : "sqdmull2", Q == 0 ? AD_INSTR_SQDMULL : AD_INSTR_SQDMULL2 }, + { Q == 0 ? "pmull" : "pmull2", Q == 0 ? AD_INSTR_PMULL : AD_INSTR_PMULL2 }, + }; + + struct itab u1_tab[] = { + { Q == 0 ? "uaddl" : "uaddl2", Q == 0 ? AD_INSTR_UADDL : AD_INSTR_UADDL2 }, + { Q == 0 ? "uaddw" : "uaddw2", Q == 0 ? AD_INSTR_UADDW : AD_INSTR_UADDW2 }, + { Q == 0 ? "usubl" : "usubl2", Q == 0 ? AD_INSTR_USUBL : AD_INSTR_USUBL2 }, + { Q == 0 ? "usubw" : "usubw2", Q == 0 ? AD_INSTR_USUBW : AD_INSTR_USUBW2 }, + { Q == 0 ? "raddhn" : "raddhn2", Q == 0 ? AD_INSTR_RADDHN : AD_INSTR_RADDHN2 }, + { Q == 0 ? "uabal" : "uabal2", Q == 0 ? AD_INSTR_UABAL : AD_INSTR_UABAL2 }, + { Q == 0 ? "rsubhn" : "rsubhn2", Q == 0 ? AD_INSTR_RSUBHN : AD_INSTR_RSUBHN2 }, + { Q == 0 ? "uabdl" : "uabdl2", Q == 0 ? AD_INSTR_UABDL : AD_INSTR_UABDL2 }, + { Q == 0 ? "umlal" : "umlal2", Q == 0 ? AD_INSTR_UMLAL : AD_INSTR_UMLAL2 }, + /* one blank, idx 9 */ + { NULL, AD_NONE }, + { Q == 0 ? "umlsl" : "umlsl2", Q == 0 ? AD_INSTR_UMLSL : AD_INSTR_UMLSL2 }, + /* one blank, idx 11 */ + { NULL, AD_NONE }, + { Q == 0 ? "umull" : "umull2", Q == 0 ? AD_INSTR_UMULL : AD_INSTR_UMULL2 }, + }; + + if(U == 0 && OOB(opcode, u0_tab)) + return 1; + + if(U == 1 && OOB(opcode, u1_tab)) + return 1; + + struct itab *tab = U == 0 ? u0_tab : u1_tab; + + instr_s = tab[opcode].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[opcode].instr_id; + + if(instr_id == AD_INSTR_SQDMLAL || instr_id == AD_INSTR_SQDMLSL || + instr_id == AD_INSTR_SQDMULL || instr_id == AD_INSTR_SQDMLAL2 || + instr_id == AD_INSTR_SQDMLSL2 || instr_id == AD_INSTR_SQDMULL2){ + if(size == 0 || size == 3) + return 1; + } + + if(instr_id == AD_INSTR_PMULL || instr_id == AD_INSTR_PMULL2){ + if(size == 1 || size == 2) + return 1; + } + + if(instr_id != AD_INSTR_PMULL && instr_id != AD_INSTR_PMULL2 && size == 3) + return 1; + + const char *Ta = NULL; + const char *Tb = NULL; + + if(size == 0){ + Ta = "8h"; + Tb = Q == 0 ? "8b" : "16b"; + } + else if(size == 1){ + Ta = "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else if(size == 2){ + Ta = "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + else if(size == 3){ + Ta = "1q"; + Tb = Q == 0 ? "1d" : "2d"; + } + + if(!Ta || !Tb) + return 1; + + if(opcode == 0 || opcode == 2 || opcode == 5 || opcode >= 7){ + first_T = Ta; + second_T = third_T = Tb; + } + else if(opcode == 1 || opcode == 3){ + first_T = second_T = Ta; + third_T = Tb; + } + else if(opcode == 4 || opcode == 6){ + first_T = Tb; + second_T = third_T = Ta; + } + + if(!first_T || !second_T || !third_T) + return 1; + + Rd_Rtbl = AD_RTBL_FP_V_128; + Rn_Rm_Rtbl = AD_RTBL_FP_V_128; + + Rd_sz = _128_BIT; + Rn_Rm_sz = _128_BIT; + } + + if(!Rd_Rtbl || !Rn_Rm_Rtbl) + return 1; + + const char *Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + const char *Rn_s = GET_FP_REG(Rn_Rm_Rtbl, Rn); + const char *Rm_s = GET_FP_REG(Rn_Rm_Rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, Rn_Rm_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_Rm_Rtbl); + ADD_REG_OPERAND(out, Rm, Rn_Rm_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_Rm_Rtbl); + + if(scalar) + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + else{ + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s", instr_s, Rd_s, + first_T, Rn_s, second_T, Rm_s, third_T); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static U64 VFPExpandImm(U32 imm8){ + const S32 N = 32; + const S32 E = 8; + const S32 F = N - E - 1; + + S32 sign = bits(imm8, 7, 7) << (1 + (E - 3) + 2 + (F - 4) + 4); + + S32 exp_p1 = (bits(imm8, 6, 6) ^ 1) << ((E - 3) + 2); + S32 exp_p2 = replicate(bits(imm8, 6, 6), 1, E - 3) << 2; + S32 exp_p3 = bits(imm8, 4, 5); + + S32 exp = (exp_p1 | exp_p2 | exp_p3) << ((F - 4) + 4); + + S32 frac = bits(imm8, 0, 4) << (F - 4); + + return sign | exp | frac; +} + +static S32 DisassembleAdvancedSIMDModifiedImmediateInstr(struct instruction *i, + struct ad_insn *out){ + U32 Q = bits(i->opcode, 30, 30); + U32 op = bits(i->opcode, 29, 29); + U32 a = bits(i->opcode, 18, 18); + U32 b = bits(i->opcode, 17, 17); + U32 c = bits(i->opcode, 16, 16); + U32 cmode = bits(i->opcode, 12, 15); + U32 o2 = bits(i->opcode, 11, 11); + U32 d = bits(i->opcode, 9, 9); + U32 e = bits(i->opcode, 8, 8); + U32 f = bits(i->opcode, 7, 7); + U32 g = bits(i->opcode, 6, 6); + U32 h = bits(i->opcode, 5, 5); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, Q); + ADD_FIELD(out, op); + ADD_FIELD(out, a); + ADD_FIELD(out, b); + ADD_FIELD(out, c); + ADD_FIELD(out, cmode); + ADD_FIELD(out, o2); + ADD_FIELD(out, d); + ADD_FIELD(out, e); + ADD_FIELD(out, f); + ADD_FIELD(out, g); + ADD_FIELD(out, h); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + U32 operation = (cmode << 1) | op; + + if(cmode == 0xf){ + if(Q == 0 && op == 1 && o2 == 0) + return 1; + + instr_s = "fmov"; + instr_id = AD_INSTR_FMOV; + } + else if((operation & ~12) == 0 || (operation & ~4) == 0x10 || (operation & ~2) == 0x18 || + (operation & ~1) == 0x1c || operation == 0x1e || operation == 0x1f){ + if(operation == 0x1f && Q == 0) + return 1; + + instr_s = "movi"; + instr_id = AD_INSTR_MOVI; + } + else if((operation & ~12) == 1 || (operation & ~4) == 0x11 || (operation & ~2) == 0x19){ + instr_s = "mvni"; + instr_id = AD_INSTR_MVNI; + } + else if((operation & ~12) == 2 || (operation & ~4) == 0x12){ + instr_s = "orr"; + instr_id = AD_INSTR_ORR; + } + else if((operation & ~12) == 3 || (operation & ~4) == 0x13){ + instr_s = "bic"; + instr_id = AD_INSTR_BIC; + } + + if(!instr_s) + return 1; + + const char **Rd_Rtbl = NULL; + U32 Rd_sz = 0; + + const char *T = NULL; + + const char *shift_s = NULL; + S32 shift_type = AD_NONE; + S32 shift_amt = AD_NONE; + + U32 imm8 = (a << 7) | (b << 6) | (c << 5) | (d << 4) | (e << 3) | + (f << 2) | (g << 1) | h; + + U64 imm = 0; + F32 immf = 0.0f; + + if(instr_id == AD_INSTR_FMOV){ + if(Q == 1 && op == 1) + T = "2d"; + else if(op == 0){ + if(o2 == 0) + T = Q == 0 ? "2s" : "4s"; + else + T = Q == 0 ? "4h" : "8h"; + } + + U32 tempimm = VFPExpandImm(imm8); + + immf = *(F32 *)&tempimm; + + Rd_Rtbl = AD_RTBL_FP_V_128; + Rd_sz = _128_BIT; + } + else{ + if(op == 0 && cmode == 14){ + T = Q == 0 ? "8b" : "16b"; + + Rd_Rtbl = AD_RTBL_FP_V_128; + Rd_sz = _128_BIT; + } + else if((cmode & ~2) == 8 || (cmode & ~2) == 9){ + T = Q == 0 ? "4h" : "8h"; + + shift_s = "lsl"; + shift_type = AD_SHIFT_LSL; + shift_amt = 8 * ((cmode >> 1) & 1); + + Rd_Rtbl = AD_RTBL_FP_V_128; + Rd_sz = _128_BIT; + } + else if((cmode & ~6) == 0 || (cmode & ~6) == 1 || (cmode & ~1) == 12){ + T = Q == 0 ? "2s" : "4s"; + + if((cmode & ~6) == 0 || (cmode & ~6) == 1){ + shift_s = "lsl"; + shift_type = AD_SHIFT_LSL; + shift_amt = 8 * bits(cmode, 1, 2); + } + else{ + shift_s = "msl"; + shift_type = AD_SHIFT_MSL; + shift_amt = 8 << (cmode & 1); + } + + Rd_Rtbl = AD_RTBL_FP_V_128; + Rd_sz = _128_BIT; + } + else if(op == 1 && cmode == 14){ + if(Q == 0){ + Rd_Rtbl = AD_RTBL_FP_64; + Rd_sz = _64_BIT; + } + else{ + T = "2d"; + + Rd_Rtbl = AD_RTBL_FP_V_128; + Rd_sz = _128_BIT; + } + } + + imm = (replicate(a, 1, 8) << 56) | (replicate(b, 1, 8) << 48) | + (replicate(c, 1, 8) << 40) | (replicate(d, 1, 8) << 32) | + (replicate(e, 1, 8) << 24) | (replicate(f, 1, 8) << 16) | + (replicate(g, 1, 8) << 8) | replicate(h, 1, 8); + } + + if(!Rd_Rtbl) + return 1; + + const char *Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + /* only instr without arrangement specifier is MOVI (64 bit scalar variant) */ + if(!(instr_id == AD_INSTR_MOVI && Q == 0 && op == 1 && cmode == 14)){ + if(!T) + return 1; + + concat(&DECODE_STR(out), ".%s", T); + } + + if(instr_id == AD_INSTR_FMOV){ + ADD_IMM_OPERAND(out, AD_IMM_FLOAT, *(U32 *)&immf); + + concat(&DECODE_STR(out), ", #%f", immf); + + /* done constructing decode string for FMOV */ + SET_INSTR_ID(out, instr_id); + + return 0; + } + + /* at this point, only instr without shift is MOVI (64 bit, both variants) */ + if(instr_id == AD_INSTR_MOVI && op == 1 && cmode == 14){ + ADD_IMM_OPERAND(out, AD_IMM_LONG, *(S64 *)&imm); + + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + + SET_INSTR_ID(out, instr_id); + + return 0; + } + + ADD_IMM_OPERAND(out, AD_IMM_INT, *(S32 *)&imm8); + + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm8)); + + if(shift_type != AD_NONE){ + if(shift_type == AD_SHIFT_MSL || (shift_type == AD_SHIFT_LSL && shift_amt > 0)){ + ADD_SHIFT_OPERAND(out, shift_type, shift_amt); + + concat(&DECODE_STR(out), ", %s #%d", shift_s, shift_amt); + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDShiftByImmediateInstr(struct instruction *i, + struct ad_insn *out, S32 scalar){ + U32 Q = bits(i->opcode, 30, 30); + U32 U = bits(i->opcode, 29, 29); + U32 immh = bits(i->opcode, 19, 22); + U32 immb = bits(i->opcode, 16, 18); + U32 opcode = bits(i->opcode, 11, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(!scalar) + ADD_FIELD(out, Q); + + ADD_FIELD(out, U); + ADD_FIELD(out, immh); + ADD_FIELD(out, immb); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + const char **rtbls[] = { + AD_RTBL_FP_8, AD_RTBL_FP_16, AD_RTBL_FP_32, AD_RTBL_FP_64 + }; + + U32 sizes[] = { + _8_BIT, _16_BIT, _32_BIT, _64_BIT + }; + + if(opcode <= 0xe){ + struct itab tab[] = { + { U == 0 ? "sshr" : "ushr", U == 0 ? AD_INSTR_SSHR : AD_INSTR_USHR }, + /* one blank, idx 1 */ + { NULL, AD_NONE }, + { U == 0 ? "ssra" : "usra", U == 0 ? AD_INSTR_SSRA : AD_INSTR_USRA }, + /* one blank, idx 3 */ + { NULL, AD_NONE }, + { U == 0 ? "srshr" : "urshr", U == 0 ? AD_INSTR_SRSHR : AD_INSTR_URSHR }, + /* one blank, idx 5 */ + { NULL, AD_NONE }, + { U == 0 ? "srsra" : "ursra", U == 0 ? AD_INSTR_SRSRA : AD_INSTR_URSRA }, + /* one blank, idx 7 */ + { NULL, AD_NONE }, + { U == 0 ? NULL : "sri", U == 0 ? AD_NONE : AD_INSTR_SRI }, + /* one blank, idx 9 */ + { NULL, AD_NONE }, + { U == 0 ? "shl" : "sli", U == 0 ? AD_INSTR_SHL : AD_INSTR_SLI }, + /* one blank, idx 11 */ + { NULL, AD_NONE }, + { U == 0 ? NULL : "sqshlu", U == 0 ? AD_NONE : AD_INSTR_SQSHLU }, + /* one blank, idx 13 */ + { NULL, AD_NONE }, + { U == 0 ? "sqshl" : "uqshl", U == 0 ? AD_INSTR_SQSHL : AD_INSTR_UQSHL }, + }; + + if(OOB(opcode, tab)) + return 1; + + instr_s = tab[opcode].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[opcode].instr_id; + + const char **rtbl = NULL; + U32 sz = 0; + + const char *T = NULL; + + U32 shift = 0; + + S32 hsb = HighestSetBit(immh, 4); + + if(scalar){ + if(instr_id != AD_INSTR_SQSHL && instr_id != AD_INSTR_SQSHLU && + instr_id != AD_INSTR_UQSHL){ + if((immh >> 3) == 0) + return 1; + + rtbl = AD_RTBL_FP_64; + sz = _64_BIT; + } + else{ + if(hsb == -1) + return 1; + + rtbl = rtbls[hsb]; + sz = sizes[hsb]; + } + } + else{ + if(immh == 1) + T = Q == 0 ? "8b" : "16b"; + else if((immh & ~1) == 2) + T = Q == 0 ? "4h" : "8h"; + else if((immh & ~3) == 4) + T = Q == 0 ? "2s" : "4s"; + else if((immh & ~7) == 8 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + + if(!rtbl) + return 1; + + if(opcode <= 8){ + if(scalar) + shift = ((8 << 3) * 2) - ((immh << 3) | immb); + else + shift = ((8 << hsb) * 2) - ((immh << 3) | immb); + } + else if(opcode > 8 && opcode <= 0xb){ + if(scalar) + shift = ((immh << 3) | immb) - (8 << 3); + else + shift = ((immh << 3) | immb) - (8 << hsb); + } + else if(opcode == 0xc || opcode == 0xe){ + shift = ((immh << 3) | immb) - (8 << hsb); + } + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(scalar) + concat(&DECODE_STR(out), ", %s", Rn_s); + else + concat(&DECODE_STR(out), ".%s, %s.%s", T, Rn_s, T); + + if(shift > 0){ + concat(&DECODE_STR(out), ", #%#x", shift); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&shift); + } + } + else if(opcode >= 0x10 && opcode <= 0x14){ + const char **Rd_Rtbl = NULL; + const char **Rn_Rtbl = NULL; + + U32 Rd_sz = 0; + U32 Rn_sz = 0; + + const char *Ta = NULL; + const char *Tb = NULL; + + S32 Ta_first = 0; + + U32 shift = 0; + + if(scalar){ + if(opcode == 0x10){ + if(U == 0) + return 1; + + instr_s = "sqshrun"; + instr_id = AD_INSTR_SQSHRUN; + } + else if(opcode == 0x11){ + if(U == 0) + return 1; + + instr_s = "sqrshrun"; + instr_id = AD_INSTR_SQRSHRUN; + } + else if(opcode == 0x12){ + instr_s = U == 0 ? "sqshrn" : "uqshrn"; + instr_id = U == 0 ? AD_INSTR_SQSHRN : AD_INSTR_UQSHRN; + } + else if(opcode == 0x13){ + instr_s = U == 0 ? "sqrshrn" : "uqrshrn"; + instr_id = U == 0 ? AD_INSTR_SQRSHRN : AD_INSTR_UQRSHRN; + } + + if(!instr_s) + return 1; + + S32 hsb = HighestSetBit(immh, 4); + + if(hsb == -1) + return 1; + + shift = (2 * (8 << hsb)) - ((immh << 3) | immb); + + if(OOB(hsb, rtbls) || OOB(hsb, sizes) || OOB(hsb + 1, rtbls) || + OOB(hsb + 1, sizes)){ + return 1; + } + + Rd_Rtbl = rtbls[hsb]; + Rn_Rtbl = rtbls[hsb + 1]; + + Rd_sz = sizes[hsb]; + Rn_sz = sizes[hsb + 1]; + } + else{ + struct itab u0_tab[] = { + { Q == 0 ? "shrn" : "shrn2", Q == 0 ? AD_INSTR_SHRN : AD_INSTR_SHRN2 }, + { Q == 0 ? "rshrn" : "rshrn2", Q == 0 ? AD_INSTR_RSHRN : AD_INSTR_RSHRN2 }, + { Q == 0 ? "sqshrn" : "sqshrn2", Q == 0 ? AD_INSTR_SQSHRN : AD_INSTR_SQSHRN2 }, + { Q == 0 ? "sqrshrn" : "sqrshrn2", Q == 0 ? AD_INSTR_SQRSHRN : AD_INSTR_SQRSHRN2 }, + { Q == 0 ? "sshll" : "sshll2", Q == 0 ? AD_INSTR_SSHLL : AD_INSTR_SSHLL2 } + }; + + struct itab u1_tab[] = { + { Q == 0 ? "sqshrun" : "sqshrun2", Q == 0 ? AD_INSTR_SQSHRUN : AD_INSTR_SQSHRUN2 }, + { Q == 0 ? "sqrshrun" : "sqrshrun2", Q == 0 ? AD_INSTR_SQRSHRUN : AD_INSTR_SQRSHRUN2 }, + { Q == 0 ? "uqshrn" : "uqshrn2", Q == 0 ? AD_INSTR_UQSHRN : AD_INSTR_UQSHRN2 }, + { Q == 0 ? "uqrshrn" : "uqrshrn2", Q == 0 ? AD_INSTR_UQRSHRN : AD_INSTR_UQRSHRN2 }, + { Q == 0 ? "ushll" : "ushll2", Q == 0 ? AD_INSTR_USHLL : AD_INSTR_USHLL2 } + }; + + U32 tempop = opcode - 0x10; + + if(U == 0 && OOB(tempop, u0_tab)) + return 1; + + if(U == 1 && OOB(tempop, u1_tab)) + return 1; + + struct itab *tab = U == 0 ? u0_tab : u1_tab; + + instr_s = tab[tempop].instr_s; + instr_id = tab[tempop].instr_id; + + S32 xshll_alias = 0; + S32 hsb = HighestSetBit(immh, 4); + + if(instr_id != AD_INSTR_SSHLL && instr_id != AD_INSTR_SSHLL2 && + instr_id != AD_INSTR_USHLL && instr_id != AD_INSTR_USHLL2){ + shift = (2 * (8 << hsb)) - ((immh << 3) | immb); + } + else{ + xshll_alias = (immb == 0 && BitCount(immh, 4) == 1); + Ta_first = 1; + + shift = ((immh << 3) | immb) - (8 << hsb); + } + + if(xshll_alias){ + if(U == 0){ + instr_s = Q == 0 ? "sxtl" : "sxtl2"; + instr_id = Q == 0 ? AD_INSTR_SXTL : AD_INSTR_SXTL2; + } + else{ + instr_s = Q == 0 ? "uxtl" : "uxtl2"; + instr_id = Q == 0 ? AD_INSTR_UXTL : AD_INSTR_UXTL2; + } + } + + if(immh == 1){ + Ta = "8h"; + Tb = Q == 0 ? "8b": "16b"; + } + else if((immh & ~1) == 2){ + Ta = "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else if((immh & ~3) == 4){ + Ta = "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + + if(!Ta || !Tb) + return 1; + + Rd_Rtbl = AD_RTBL_FP_V_128; + Rn_Rtbl = AD_RTBL_FP_V_128; + + Rd_sz = _128_BIT; + Rn_sz = _128_BIT; + } + + if(!Rd_Rtbl || !Rn_Rtbl) + return 1; + + const char *Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + const char *Rn_s = GET_FP_REG(Rn_Rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, Rn_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_Rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(scalar) + concat(&DECODE_STR(out), ", %s", Rn_s); + else{ + concat(&DECODE_STR(out), ".%s, %s.%s", Ta_first ? Ta : Tb, + Rn_s, Ta_first ? Tb : Ta); + } + + if(shift > 0){ + concat(&DECODE_STR(out), ", #%#x", shift); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&shift); + } + } + else if(opcode == 0x1c || opcode == 0x1f){ + if(opcode == 0x1c){ + instr_s = U == 0 ? "scvtf" : "ucvtf"; + instr_id = U == 0 ? AD_INSTR_SCVTF : AD_INSTR_UCVTF; + } + else{ + instr_s = U == 0 ? "fcvtzs" : "fcvtzu"; + instr_id = U == 0 ? AD_INSTR_FCVTZS : AD_INSTR_FCVTZU; + } + + const char **rtbl = NULL; + U32 sz = 0; + + const char *T = NULL; + + S32 hsb = HighestSetBit(immh, 4); + + if(hsb <= 0) + return 1; + + U32 fbits = ((8 << hsb) * 2) - ((immh << 3) | immb); + + if(scalar){ + rtbl = rtbls[hsb]; + sz = sizes[hsb]; + } + else{ + if((immh & ~1) == 2) + T = Q == 0 ? "4h" : "8h"; + else if((immh & ~3) == 4) + T = Q == 0 ? "2s" : "4s"; + else if((immh & ~7) == 8 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + rtbl = AD_RTBL_FP_V_128; + sz = _128_BIT; + } + + if(!rtbl) + return 1; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(scalar) + concat(&DECODE_STR(out), ", %s", Rn_s); + else + concat(&DECODE_STR(out), ".%s, %s.%s", T, Rn_s, T); + + if(fbits > 0){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&fbits); + + concat(&DECODE_STR(out), ", #%#x", fbits); + } + } + else{ + return 1; + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDXIndexedElementInstr(struct instruction *i, + struct ad_insn *out, S32 scalar){ + U32 Q = bits(i->opcode, 30, 30); + U32 U = bits(i->opcode, 29, 29); + U32 size = bits(i->opcode, 22, 23); + U32 L = bits(i->opcode, 21, 21); + U32 M = bits(i->opcode, 20, 20); + U32 Rm = bits(i->opcode, 16, 19); + U32 opcode = bits(i->opcode, 12, 15); + U32 H = bits(i->opcode, 11, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(!scalar) + ADD_FIELD(out, Q); + + ADD_FIELD(out, U); + ADD_FIELD(out, size); + ADD_FIELD(out, L); + ADD_FIELD(out, M); + ADD_FIELD(out, Rm); + ADD_FIELD(out, opcode); + ADD_FIELD(out, H); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + const char **Rd_Rtbl = NULL; + const char **Rn_Rtbl = NULL; + const char **Rm_Rtbl = AD_RTBL_FP_V_128; + + U32 Rd_sz = 0; + U32 Rn_sz = 0; + U32 Rm_sz = _128_BIT; + + U32 s = size >> 1; + U32 _sz = (size & 1); + + const char *Ta = NULL; + const char *Tb = NULL; + const char *Ts = NULL; + + const char *T = NULL; + S32 only_T = 0; + + U32 rotate = 90 * bits(i->opcode, 13, 14); + + U32 index = 0; + + if((U == 1 && opcode == 0) || opcode == 2 || (U == 0 && opcode == 3) || + (U == 1 && opcode == 4) || opcode == 6 || + (U == 0 && opcode == 7) || (U == 0 && opcode == 8) || opcode == 10 || + (U == 0 && opcode == 11) || (U == 0 && opcode == 12) || opcode == 13 || + opcode == 14 || (U == 1 && opcode == 15)){ + if(opcode == 0){ + if(scalar) + return 1; + + instr_s = "mla"; + instr_id = AD_INSTR_MLA; + + only_T = 1; + } + else if(opcode == 2){ + if(scalar) + return 1; + + if(U == 0){ + instr_s = Q == 0 ? "smlal" : "smlal2"; + instr_id = Q == 0 ? AD_INSTR_SMLAL : AD_INSTR_SMLAL2; + } + else{ + instr_s = Q == 0 ? "umlal" : "umlal2"; + instr_id = Q == 0 ? AD_INSTR_UMLAL : AD_INSTR_UMLAL2; + } + } + else if(opcode == 3){ + if(scalar){ + instr_s = "sqdmlal"; + instr_id = AD_INSTR_SQDMLAL; + } + else{ + instr_s = Q == 0 ? "sqdmlal" : "sqdmlal2"; + instr_id = Q == 0 ? AD_INSTR_SQDMLAL : AD_INSTR_SQDMLAL2; + } + } + else if(opcode == 4){ + instr_s = "mls"; + instr_id = AD_INSTR_MLS; + + only_T = 1; + } + else if(opcode == 6){ + if(scalar) + return 1; + + if(U == 0){ + instr_s = Q == 0 ? "smlsl" : "smlsl2"; + instr_id = Q == 0 ? AD_INSTR_SMLSL : AD_INSTR_SMLSL2; + } + else{ + instr_s = Q == 0 ? "umlsl" : "umlsl2"; + instr_id = Q == 0 ? AD_INSTR_UMLSL : AD_INSTR_UMLSL2; + } + } + else if(opcode == 7){ + if(scalar){ + instr_s = "sqdmlsl"; + instr_id = AD_INSTR_SQDMLSL; + } + else{ + instr_s = Q == 0 ? "sqdmlsl" : "sqdmlsl2"; + instr_id = Q == 0 ? AD_INSTR_SQDMLSL : AD_INSTR_SQDMLSL2; + } + } + else if(opcode == 8){ + instr_s = "mul"; + instr_id = AD_INSTR_MUL; + + only_T = 1; + } + else if(opcode == 10){ + if(scalar) + return 1; + + if(U == 0){ + instr_s = Q == 0 ? "smull" : "smull2"; + instr_id = Q == 0 ? AD_INSTR_SMULL : AD_INSTR_SMULL2; + } + else{ + instr_s = Q == 0 ? "umull" : "umull2"; + instr_id = Q == 0 ? AD_INSTR_UMULL : AD_INSTR_UMULL2; + } + } + else if(opcode == 11){ + if(scalar){ + instr_s = "sqdmull"; + instr_id = AD_INSTR_SQDMULL; + } + else{ + instr_s = Q == 0 ? "sqdmull" : "sqdmull2"; + instr_id = Q == 0 ? AD_INSTR_SQDMULL : AD_INSTR_SQDMULL2; + } + } + else if(opcode == 12){ + instr_s = "sqdmulh"; + instr_id = AD_INSTR_SQDMULH; + + only_T = 1; + } + else if(opcode == 13){ + instr_s = U == 0 ? "sqrdmulh" : "sqrdmlah"; + instr_id = U == 0 ? AD_INSTR_SQRDMULH : AD_INSTR_SQRDMLAH; + + only_T = 1; + } + else if(opcode == 14){ + if(scalar || size != 2) + return 1; + + instr_s = U == 0 ? "sdot" : "udot"; + instr_id = U == 0 ? AD_INSTR_SDOT : AD_INSTR_UDOT; + } + else if(opcode == 15){ + instr_s = "sqrdmlsh"; + instr_id = AD_INSTR_SQRDMLSH; + + only_T = 1; + } + + U32 Rmhi; + + switch(size){ + case 1: + { + index = (H << 2) | (L << 1) | M; + Rmhi = 0; + break; + } + case 2: + { + index = (H << 1) | L; + Rmhi = M; + break; + } + default: return 1; + }; + + Rm |= (Rmhi << 4); + + if(instr_id == AD_INSTR_SDOT || instr_id == AD_INSTR_UDOT){ + Ta = Q == 0 ? "2s" : "4s"; + Tb = Q == 0 ? "8b" : "16b"; + + Ts = "4b"; + } + else{ + if(size == 1){ + Ta = "4s"; + Tb = Q == 0 ? "4h" : "8h"; + } + else{ + Ta = "2d"; + Tb = Q == 0 ? "2s" : "4s"; + } + + Ts = size == 1 ? "h" : "s"; + + T = Tb; + } + } + else if(size == 2 && (opcode == 0 || opcode == 4 || opcode == 8 || opcode == 12)){ + if(opcode == 0 || opcode == 8){ + instr_s = opcode == 0 ? "fmlal" : "fmlal2"; + instr_id = opcode == 0 ? AD_INSTR_FMLAL : AD_INSTR_FMLAL2; + } + else{ + instr_s = opcode == 8 ? "fmlsl" : "fmlsl2"; + instr_id = opcode == 8 ? AD_INSTR_FMLSL : AD_INSTR_FMLSL2; + } + + index = (H << 2) | (L << 1) | M; + + Ta = Q == 0 ? "2s" : "4s"; + Tb = Q == 0 ? "2h" : "4h"; + + Ts = "h"; + } + else if((U == 0 && opcode == 1) || (U == 0 && opcode == 5) || opcode == 9){ + if(opcode == 1){ + instr_s = "fmla"; + instr_id = AD_INSTR_FMLA; + } + else if(opcode == 5){ + instr_s = "fmls"; + instr_id = AD_INSTR_FMLS; + } + else if(opcode == 9){ + instr_s = U == 0 ? "fmul" : "fmulx"; + instr_id = U == 0 ? AD_INSTR_FMUL : AD_INSTR_FMULX; + } + + if(s == 0){ + index = (H << 2) | (L << 1) | M; + + T = Q == 0 ? "4h" : "8h"; + Ts = "h"; + } + else{ + U32 Rmhi = M; + U32 size = (_sz << 1) | L; + + if((size & ~1) == 0) + index = (H << 1) | L; + else if(size == 2) + index = H; + else if(size == 3) + return 1; + + if(_sz == 0) + T = Q == 0 ? "2s" : "4s"; + else if(_sz == 1 && Q == 1) + T = "2d"; + else + return 1; + + Ts = _sz == 0 ? "s" : "d"; + + Rm |= (Rmhi << 4); + } + + only_T = 1; + } + else if(U == 1 && (size == 1 || size == 2) && (opcode & ~6) == 1){ + instr_s = "fcmla"; + instr_id = AD_INSTR_FCMLA; + + if(size == 1){ + index = (H << 1) | L; + + T = Q == 0 ? "4h" : "8h"; + Ts = "h"; + } + else{ + index = H; + + T = "4s"; + Ts = "s"; + } + + Rm |= (M << 4); + + only_T = 1; + } + + if(!instr_s) + return 1; + + if(scalar){ + if(instr_id == AD_INSTR_SQDMLAL || instr_id == AD_INSTR_SQDMLSL || + instr_id == AD_INSTR_SQDMULL){ + Rd_Rtbl = size == 1 ? AD_RTBL_FP_32 : AD_RTBL_FP_64; + Rn_Rtbl = size == 1 ? AD_RTBL_FP_16 : AD_RTBL_FP_32; + + Rd_sz = size == 1 ? _32_BIT : _64_BIT; + Rn_sz = size == 1 ? _16_BIT : _32_BIT; + } + else if(instr_id == AD_INSTR_FMLA || instr_id == AD_INSTR_FMLS || + instr_id == AD_INSTR_FMUL || instr_id == AD_INSTR_FMULX){ + if(s == 0){ + Rd_Rtbl = AD_RTBL_FP_16; + Rn_Rtbl = Rd_Rtbl; + + Rd_sz = _16_BIT; + Rn_sz = Rd_sz; + } + else{ + Rd_Rtbl = _sz == 0 ? AD_RTBL_FP_32 : AD_RTBL_FP_64; + Rn_Rtbl = Rd_Rtbl; + + Rd_sz = _sz == 0 ? _32_BIT : _64_BIT; + Rn_sz = Rd_sz; + } + } + else{ + Rd_Rtbl = size == 1 ? AD_RTBL_FP_16 : AD_RTBL_FP_32; + Rn_Rtbl = Rd_Rtbl; + + Rd_sz = size == 1 ? _16_BIT : _32_BIT; + Rn_sz = Rd_sz; + } + } + else{ + Rd_Rtbl = AD_RTBL_FP_V_128; + Rn_Rtbl = Rd_Rtbl; + + Rd_sz = _128_BIT; + Rn_sz = Rd_sz; + } + + if(!Rd_Rtbl || !Rn_Rtbl) + return 1; + + const char *Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + const char *Rn_s = GET_FP_REG(Rn_Rtbl, Rn); + const char *Rm_s = GET_FP_REG(Rm_Rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, Rn_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_Rtbl); + ADD_REG_OPERAND(out, Rm, Rm_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rm_Rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(scalar) + concat(&DECODE_STR(out), ", %s", Rn_s); + else{ + if(only_T) + concat(&DECODE_STR(out), ".%s, %s.%s", T, Rn_s, T); + else + concat(&DECODE_STR(out), ".%s, %s.%s", Ta, Rn_s, Tb); + } + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&index); + concat(&DECODE_STR(out), ", %s.%s[%d]", Rm_s, Ts, index); + + if(instr_id == AD_INSTR_FCMLA){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&rotate); + concat(&DECODE_STR(out), ", #%d", rotate); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDTableLookupInstr(struct instruction *i, + struct ad_insn *out){ + U32 Q = bits(i->opcode, 30, 30); + U32 op2 = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 len = bits(i->opcode, 13, 14); + U32 op = bits(i->opcode, 12, 12); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(op2 != 0) + return 1; + + ADD_FIELD(out, Q); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rm); + ADD_FIELD(out, len); + ADD_FIELD(out, op); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = op == 0 ? "tbl" : "tbx"; + S32 instr_id = op == 0 ? AD_INSTR_TBL : AD_INSTR_TBX; + + const char *Ta = Q == 0 ? "8b" : "16b"; + + const char **rtbl = AD_RTBL_FP_V_128; + U32 sz = _128_BIT; + + len++; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s.%s, {", instr_s, Rd_s, Ta); + + for(S32 i=Rn; i<(Rn+len); i++){ + const char *Rn_s = GET_FP_REG(rtbl, i); + ADD_REG_OPERAND(out, i, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + if(i == (Rn+len) - 1) + concat(&DECODE_STR(out), " %s.16b", Rn_s); + else + concat(&DECODE_STR(out), " %s.16b,", Rn_s); + } + + const char *Rm_s = GET_FP_REG(rtbl, Rm); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), " }, %s.%s", Rm_s, Ta); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDPermuteInstr(struct instruction *i, + struct ad_insn *out){ + U32 Q = bits(i->opcode, 30, 30); + U32 size = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 12, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, Q); + ADD_FIELD(out, size); + ADD_FIELD(out, Rm); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + /* one blank, idx 0 */ + { NULL, AD_NONE }, + { "uzp1", AD_INSTR_UZP1 }, { "trn1", AD_INSTR_TRN1 }, + { "zip1", AD_INSTR_ZIP1 }, + /* one blank, idx 4 */ + { NULL, AD_NONE }, + { "uzp2", AD_INSTR_UZP2 }, { "trn2", AD_INSTR_TRN2 }, + { "zip2", AD_INSTR_ZIP2 }, + }; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + + if(!instr_s) + return 1; + + S32 instr_id = tab[opcode].instr_id; + + const char **rtbl = AD_RTBL_FP_V_128; + U32 sz = _128_BIT; + + const char *T = NULL; + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2) + T = Q == 0 ? "2s" : "4s"; + else if(size == 3 && Q == 1) + T = "2d"; + + if(!T) + return 1; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s", instr_s, Rd_s, T, Rn_s, + T, Rm_s, T); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAdvancedSIMDExtractInstr(struct instruction *i, + struct ad_insn *out){ + U32 Q = bits(i->opcode, 30, 30); + U32 op2 = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 imm4 = bits(i->opcode, 11, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(op2 != 0) + return 1; + + if(Q == 0 && ((imm4 >> 3) & 1) == 1) + return 1; + + ADD_FIELD(out, Q); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rm); + ADD_FIELD(out, imm4); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *T = Q == 0 ? "8b" : "16b"; + + const char **rtbl = AD_RTBL_FP_V_128; + U32 sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + S32 index = sign_extend(imm4, 4); + + ADD_IMM_OPERAND(out, AD_IMM_INT, *(S32 *)&index); + + concat(&DECODE_STR(out), "ext %s.%s, %s.%s, %s.%s, #"S_X"", Rd_s, T, Rn_s, + T, Rm_s, T, S_A(index)); + + SET_INSTR_ID(out, AD_INSTR_EXT); + + return 0; +} + +static S32 DisassembleAdvancedSIMDAcrossLanesInstr(struct instruction *i, + struct ad_insn *out){ + U32 Q = bits(i->opcode, 30, 30); + U32 U = bits(i->opcode, 29, 29); + U32 size = bits(i->opcode, 22, 23); + U32 opcode = bits(i->opcode, 12, 16); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, Q); + ADD_FIELD(out, U); + ADD_FIELD(out, size); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + const char **Rd_Rtbl = NULL; + U32 Rd_sz = 0; + + const char *T = NULL; + + if(opcode == 3 || opcode == 10 || opcode == 0x1a || opcode == 0x1b){ + if(size == 3) + return 1; + + const char **rtbls_o3[] = { + AD_RTBL_FP_16, AD_RTBL_FP_32, AD_RTBL_FP_64 + }; + + const char **rtbls[] = { + AD_RTBL_FP_8, AD_RTBL_FP_16, AD_RTBL_FP_32 + }; + + U32 sizes_o3[] = { + _16_BIT, _32_BIT, _64_BIT + }; + + U32 sizes[] = { + _8_BIT, _16_BIT, _32_BIT + }; + + if(opcode == 3){ + instr_s = U == 0 ? "saddlv" : "uaddlv"; + instr_id = U == 0 ? AD_INSTR_SADDLV : AD_INSTR_UADDLV; + } + else if(opcode == 10){ + instr_s = U == 0 ? "smaxv" : "umaxv"; + instr_id = U == 0 ? AD_INSTR_SMAXV : AD_INSTR_UMAXV; + } + else if(opcode == 0x1a){ + instr_s = U == 0 ? "sminv" : "uminv"; + instr_id = U == 0 ? AD_INSTR_SMINV : AD_INSTR_UMINV; + } + else{ + if(U == 1) + return 1; + + instr_s = "addv"; + instr_id = AD_INSTR_ADDV; + } + + if(opcode == 3){ + Rd_Rtbl = rtbls_o3[size]; + Rd_sz = sizes_o3[size]; + } + else{ + Rd_Rtbl = rtbls[size]; + Rd_sz = sizes[size]; + } + + if(size == 0) + T = Q == 0 ? "8b" : "16b"; + else if(size == 1) + T = Q == 0 ? "4h" : "8h"; + else if(size == 2 && Q == 1) + T = "4s"; + } + else{ + if(opcode != 12 && opcode != 15) + return 1; + + if(U == 0 && (size == 1 || size == 3)) + return 1; + + U32 sz = (size & 1); + + if(sz == 1) + return 1; + + if(U == 0){ + T = Q == 0 ? "4h" : "8h"; + + Rd_Rtbl = AD_RTBL_FP_16; + Rd_sz = _16_BIT; + } + else{ + if(Q == 1) + T = "4s"; + + Rd_Rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + } + + U32 s = size >> 1; + U32 compar = U == 0 ? size : s; + + if(opcode == 12){ + instr_s = compar == 0 ? "fmaxnmv" : "fminnmv"; + instr_id = compar == 0 ? AD_INSTR_FMAXNMV : AD_INSTR_FMINNMV; + } + else{ + instr_s = compar == 0 ? "fmaxv" : "fminv"; + instr_id = compar == 0 ? AD_INSTR_FMAXV : AD_INSTR_FMINV; + } + } + + if(!Rd_Rtbl || !T) + return 1; + + const char *Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_V_128, Rn); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + concat(&DECODE_STR(out), "%s %s, %s.%s", instr_s, Rd_s, Rn_s, T); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleCryptographicThreeRegisterImm2Instr(struct instruction *i, + struct ad_insn *out){ + U32 Rm = bits(i->opcode, 16, 20); + U32 imm2 = bits(i->opcode, 12, 13); + U32 opcode = bits(i->opcode, 10, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, Rm); + ADD_FIELD(out, imm2); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + { "sm3tt1a", AD_INSTR_SM3TT1A }, { "sm3tt1b", AD_INSTR_SM3TT1B }, + { "sm3tt2a", AD_INSTR_SM3TT2A }, { "sm3tt2b", AD_INSTR_SM3TT2B } + }; + + const char *instr_s = tab[opcode].instr_s; + S32 instr_id = tab[opcode].instr_id; + + const char **rtbl = AD_RTBL_FP_V_128; + U32 sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm2); + + concat(&DECODE_STR(out), "%s %s.4s, %s.4s, %s.s[%d]", instr_s, Rd_s, Rn_s, + Rm_s, imm2); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleCryptographicThreeRegisterSHA512Instr(struct instruction *i, + struct ad_insn *out){ + U32 Rm = bits(i->opcode, 16, 20); + U32 O = bits(i->opcode, 14, 14); + U32 opcode = bits(i->opcode, 10, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, Rm); + ADD_FIELD(out, O); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + U32 idx = (O << 2) | opcode; + + struct itab tab[] = { + { "sha512h", AD_INSTR_SHA512H }, { "sha512h2", AD_INSTR_SHA512H2 }, + { "sha512su1", AD_INSTR_SHA512SU1 }, { "rax1", AD_INSTR_RAX1 }, + { "sm3partw1", AD_INSTR_SM3PARTW1 }, { "sm3partw2", AD_INSTR_SM3PARTW2 }, + { "sm4ekey", AD_INSTR_SM4EKEY } + }; + + if(OOB(idx, tab)) + return 1; + + const char *instr_s = tab[idx].instr_s; + S32 instr_id = tab[idx].instr_id; + + const char **Rd_Rtbl = NULL; + const char **Rn_Rtbl = NULL; + + if(instr_id == AD_INSTR_SHA512H || instr_id == AD_INSTR_SHA512H2){ + Rd_Rtbl = AD_RTBL_FP_128; + Rn_Rtbl = AD_RTBL_FP_128; + } + else{ + Rd_Rtbl = AD_RTBL_FP_V_128; + Rn_Rtbl = AD_RTBL_FP_V_128; + } + + const char *T = NULL; + S32 T_on_all = 1; + + if(instr_id != AD_INSTR_SM3PARTW1 && instr_id != AD_INSTR_SM3PARTW2 && + instr_id != AD_INSTR_SM4EKEY){ + T = "2d"; + T_on_all = (instr_id != AD_INSTR_SHA512H && instr_id != AD_INSTR_SHA512H2); + } + else{ + T = "4s"; + } + + const char **Rm_Rtbl = AD_RTBL_FP_V_128; + + U32 sz = _128_BIT; + + const char *Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + const char *Rn_s = GET_FP_REG(Rn_Rtbl, Rn); + const char *Rm_s = GET_FP_REG(Rm_Rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_Rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rm_Rtbl); + + concat(&DECODE_STR(out), "%s", instr_s); + + if(T_on_all) + concat(&DECODE_STR(out), " %s.%s, %s.%s, %s.%s", Rd_s, T, Rn_s, T, Rm_s, T); + else + concat(&DECODE_STR(out), " %s, %s, %s.%s", Rd_s, Rn_s, Rm_s, T); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleCryptographicFourRegisterInstr(struct instruction *i, + struct ad_insn *out){ + U32 Op0 = bits(i->opcode, 21, 22); + U32 Rm = bits(i->opcode, 16, 20); + U32 Ra = bits(i->opcode, 10, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(Op0 == 3) + return 1; + + ADD_FIELD(out, Op0); + ADD_FIELD(out, Rm); + ADD_FIELD(out, Ra); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + const char *T = NULL; + + if(Op0 == 0){ + instr_s = "eor3"; + instr_id = AD_INSTR_EOR3; + + T = "16b"; + } + else if(Op0 == 1){ + instr_s = "bcax"; + instr_id = AD_INSTR_BCAX; + + T = "16b"; + } + else{ + instr_s = "sm3ss1"; + instr_id = AD_INSTR_SM3SS1; + + T = "4s"; + } + + const char *Rd_s = GET_FP_REG(AD_RTBL_FP_V_128, Rd); + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_V_128, Rn); + const char *Rm_s = GET_FP_REG(AD_RTBL_FP_V_128, Rm); + const char *Ra_s = GET_FP_REG(AD_RTBL_FP_V_128, Ra); + + ADD_REG_OPERAND(out, Rd, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + ADD_REG_OPERAND(out, Rm, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + ADD_REG_OPERAND(out, Ra, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s, %s.%s, %s.%s", instr_s, Rd_s, T, + Rn_s, T, Rm_s, T, Ra_s, T); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleXARInstr(struct instruction *i, struct ad_insn *out){ + U32 Rm = bits(i->opcode, 16, 20); + U32 imm6 = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, Rm); + ADD_FIELD(out, imm6); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *Rd_s = GET_FP_REG(AD_RTBL_FP_V_128, Rd); + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_V_128, Rn); + const char *Rm_s = GET_FP_REG(AD_RTBL_FP_V_128, Rm); + + ADD_REG_OPERAND(out, Rd, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + ADD_REG_OPERAND(out, Rm, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm6); + + concat(&DECODE_STR(out), "xar %s.2d, %s.2d, %s.2d, #"S_X"", Rd_s, Rn_s, + Rm_s, S_A(imm6)); + + SET_INSTR_ID(out, AD_INSTR_XAR); + + return 0; +} + +static S32 DisassembleCryptographicTwoRegisterSHA512Instr(struct instruction *i, + struct ad_insn *out){ + U32 opcode = bits(i->opcode, 10, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(opcode > 1) + return 1; + + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + const char *T = NULL; + + if(opcode == 0){ + instr_s = "sha512su0"; + instr_id = AD_INSTR_SHA512SU0; + + T = "2d"; + } + else{ + instr_s = "sm4e"; + instr_id = AD_INSTR_SM4E; + + T = "4s"; + } + + const char *Rd_s = GET_FP_REG(AD_RTBL_FP_V_128, Rd); + const char *Rn_s = GET_FP_REG(AD_RTBL_FP_V_128, Rn); + + ADD_REG_OPERAND(out, Rd, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + ADD_REG_OPERAND(out, Rn, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + + concat(&DECODE_STR(out), "%s %s.%s, %s.%s", instr_s, Rd_s, T, Rn_s, T); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleConversionBetweenFloatingPointAndFixedPointInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 rmode = bits(i->opcode, 19, 20); + U32 opcode = bits(i->opcode, 16, 18); + U32 scale = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(opcode > 3) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, rmode); + ADD_FIELD(out, opcode); + ADD_FIELD(out, scale); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(opcode == 0){ + instr_s = "fcvtzs"; + instr_id = AD_INSTR_FCVTZS; + } + else if(opcode == 1){ + instr_s = "fcvtzu"; + instr_id = AD_INSTR_FCVTZU; + } + else if(opcode == 2){ + instr_s = "scvtf"; + instr_id = AD_INSTR_SCVTF; + } + else if(opcode == 3){ + instr_s = "ucvtf"; + instr_id = AD_INSTR_UCVTF; + } + + const char **Rd_Rtbl = NULL; + const char **Rn_Rtbl = NULL; + + U32 Rd_sz = 0; + U32 Rn_sz = 0; + + U32 ftype = ptype; + + if(ftype == 2) + return 1; + + if(instr_id == AD_INSTR_FCVTZS || instr_id == AD_INSTR_FCVTZU){ + Rd_Rtbl = sf == 0 ? AD_RTBL_GEN_32 : AD_RTBL_GEN_64; + Rd_sz = sf == 0 ? _32_BIT : _64_BIT; + + if(ftype == 0){ + Rn_Rtbl = AD_RTBL_FP_32; + Rn_sz = _32_BIT; + } + else if(ftype == 1){ + Rn_Rtbl = AD_RTBL_FP_64; + Rn_sz = _64_BIT; + } + else{ + Rn_Rtbl = AD_RTBL_FP_16; + Rn_sz = _16_BIT; + } + } + else{ + Rn_Rtbl = sf == 0 ? AD_RTBL_GEN_32 : AD_RTBL_GEN_64; + Rn_sz = sf == 0 ? _32_BIT : _64_BIT; + + if(ftype == 0){ + Rd_Rtbl = AD_RTBL_FP_32; + Rd_sz = _32_BIT; + } + else if(ftype == 1){ + Rd_Rtbl = AD_RTBL_FP_64; + Rd_sz = _64_BIT; + } + else{ + Rd_Rtbl = AD_RTBL_FP_16; + Rd_sz = _16_BIT; + } + } + + if(!Rd_Rtbl || !Rn_Rtbl) + return 1; + + const char *Rd_s = NULL; + const char *Rn_s = NULL; + + if(instr_id == AD_INSTR_FCVTZS || instr_id == AD_INSTR_FCVTZU){ + Rd_s = GET_GEN_REG(Rd_Rtbl, Rd, PREFER_ZR); + Rn_s = GET_FP_REG(Rn_Rtbl, Rn); + } + else{ + Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + Rn_s = GET_GEN_REG(Rn_Rtbl, Rn, PREFER_ZR); + } + + ADD_REG_OPERAND(out, Rd, Rd_sz, PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, Rn_sz, PREFER_ZR, _SYSREG(AD_NONE), Rn_Rtbl); + + U32 fbits = 64 - scale; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&fbits); + + concat(&DECODE_STR(out), "%s %s, %s, #%#x", instr_s, Rd_s, Rn_s, fbits); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleConversionBetweenFloatingPointAndIntegerInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 rmode = bits(i->opcode, 19, 20); + U32 opcode = bits(i->opcode, 16, 18); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, sf); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, rmode); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + U32 operation = (bits(opcode, 1, 2) << 2) | rmode; + U32 u = (opcode & 1); + + /* if this is zero, S32 to float */ + S32 float_to_int = 0; + /* append .d[1]? */ + S32 part = 0; + + const char **Flt_Rtbl = NULL; + const char **Gen_Rtbl = sf == 0 ? AD_RTBL_GEN_32 : AD_RTBL_GEN_64; + + U32 ftype = ptype; + + U32 intsize = sf == 0 ? _32_BIT : _64_BIT; + U32 fltsize; + + if(ftype == 0){ + Flt_Rtbl = AD_RTBL_FP_32; + fltsize = _32_BIT; + } + else if(ftype == 1){ + Flt_Rtbl = AD_RTBL_FP_64; + fltsize = _64_BIT; + } + else if(ftype == 2){ + if(operation != 13) + return 1; + + Flt_Rtbl = AD_RTBL_FP_V_128; + fltsize = _128_BIT; + } + else{ + Flt_Rtbl = AD_RTBL_FP_16; + fltsize = _16_BIT; + } + + if((operation & ~3) == 0){ + /* fcvt[npmz][us] */ + if(rmode == 0){ + instr_s = u == 0 ? "fcvtns" : "fcvtnu"; + instr_id = u == 0 ? AD_INSTR_FCVTNS : AD_INSTR_FCVTNU; + } + else if(rmode == 1){ + instr_s = u == 0 ? "fcvtps" : "fcvtpu"; + instr_id = u == 0 ? AD_INSTR_FCVTPS : AD_INSTR_FCVTPU; + } + else if(rmode == 2){ + instr_s = u == 0 ? "fcvtms" : "fcvtmu"; + instr_id = u == 0 ? AD_INSTR_FCVTMS : AD_INSTR_FCVTMU; + } + else{ + instr_s = u == 0 ? "fcvtzs" : "fcvtzu"; + instr_id = u == 0 ? AD_INSTR_FCVTZS : AD_INSTR_FCVTZU; + } + + float_to_int = 1; + } + else if(operation == 4){ + instr_s = u == 0 ? "scvtf" : "ucvtf"; + instr_id = u == 0 ? AD_INSTR_SCVTF : AD_INSTR_UCVTF; + } + else if(operation == 8){ + instr_s = u == 0 ? "fcvtas" : "fcvtau"; + instr_id = u == 0 ? AD_INSTR_FCVTAS : AD_INSTR_FCVTAU; + + float_to_int = 1; + } + else if(operation == 12 || operation == 13){ + instr_s = "fmov"; + instr_id = AD_INSTR_FMOV; + + if((opcode & 1) == 0) + float_to_int = 1; + + if(operation == 13) + part = 1; + } + else if(operation == 15){ + instr_s = "fjcvtzs"; + instr_id = AD_INSTR_FJCVTZS; + + float_to_int = 1; + } + else{ + return 1; + } + + const char **Rd_Rtbl = NULL; + const char **Rn_Rtbl = NULL; + + U32 Rd_sz = 0; + U32 Rn_sz = 0; + + const char *Rd_s = NULL; + const char *Rn_s = NULL; + + if(float_to_int){ + Rd_Rtbl = Gen_Rtbl; + Rn_Rtbl = Flt_Rtbl; + + Rd_sz = intsize; + Rn_sz = fltsize; + + Rd_s = GET_GEN_REG(Rd_Rtbl, Rd, PREFER_ZR); + Rn_s = GET_FP_REG(Rn_Rtbl, Rn); + } + else{ + Rd_Rtbl = Flt_Rtbl; + Rn_Rtbl = Gen_Rtbl; + + Rd_sz = fltsize; + Rn_sz = intsize; + + Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + Rn_s = GET_GEN_REG(Rn_Rtbl, Rn, PREFER_ZR); + } + + ADD_REG_OPERAND(out, Rd, Rd_sz, PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(!float_to_int && part){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, 1); + concat(&DECODE_STR(out), ".d[1]"); + } + + ADD_REG_OPERAND(out, Rn, Rn_sz, PREFER_ZR, _SYSREG(AD_NONE), Rn_Rtbl); + + concat(&DECODE_STR(out), ", %s", Rn_s); + + if(float_to_int && part){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, 1); + concat(&DECODE_STR(out), ".d[1]"); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleFloatingPointDataProcessingOneSourceInstr(struct instruction *i, + struct ad_insn *out){ + U32 M = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 opcode = bits(i->opcode, 15, 20); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(M == 1 || S == 1 || ptype == 2) + return 1; + + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + struct itab *tab = NULL; + + struct itab ptype0_tab[] = { + { "fmov", AD_INSTR_FMOV }, { "fabs", AD_INSTR_FABS }, + { "fneg", AD_INSTR_FNEG }, { "fsqrt", AD_INSTR_FSQRT }, + /* one blank, idx 4 */ + { NULL, AD_NONE }, + { "fcvt", AD_INSTR_FCVT }, + /* one blank, idx 6 */ + { NULL, AD_NONE }, + { "fcvt", AD_INSTR_FCVT }, { "frintn", AD_INSTR_FRINTN }, + { "frintp", AD_INSTR_FRINTP }, { "frintm", AD_INSTR_FRINTM }, + { "frintz", AD_INSTR_FRINTZ }, { "frinta", AD_INSTR_FRINTA }, + /* one blank, idx 13 */ + { NULL, AD_NONE }, + { "frintx", AD_INSTR_FRINTX }, { "frinti", AD_INSTR_FRINTI }, + { "frint32z", AD_INSTR_FRINT32Z }, { "frint32x", AD_INSTR_FRINT32X }, + { "frint64z", AD_INSTR_FRINT64Z }, { "frint64x", AD_INSTR_FRINT64X } + }; + + struct itab ptype1_tab[] = { + { "fmov", AD_INSTR_FMOV }, { "fabs", AD_INSTR_FABS }, + { "fneg", AD_INSTR_FNEG }, { "fsqrt", AD_INSTR_FSQRT }, + { "fcvt", AD_INSTR_FCVT }, + /* two blanks, idxes [5-6] */ + { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "fcvt", AD_INSTR_FCVT }, { "frintn", AD_INSTR_FRINTN }, + { "frintp", AD_INSTR_FRINTP }, { "frintm", AD_INSTR_FRINTM }, + { "frintz", AD_INSTR_FRINTZ }, { "frinta", AD_INSTR_FRINTA }, + /* one blank, idx 13 */ + { NULL, AD_NONE }, + { "frintx", AD_INSTR_FRINTX }, { "frinti", AD_INSTR_FRINTI }, + { "frint32z", AD_INSTR_FRINT32Z }, { "frint32x", AD_INSTR_FRINT32X }, + { "frint64z", AD_INSTR_FRINT64Z }, { "frint64x", AD_INSTR_FRINT64X } + }; + + struct itab ptype3_tab[] = { + { "fmov", AD_INSTR_FMOV }, { "fabs", AD_INSTR_FABS }, + { "fneg", AD_INSTR_FNEG }, { "fsqrt", AD_INSTR_FSQRT }, + { "fcvt", AD_INSTR_FCVT }, + { "fcvt", AD_INSTR_FCVT }, + /* two blanks, idxes [6-7] */ + { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "frintn", AD_INSTR_FRINTN }, + { "frintp", AD_INSTR_FRINTP }, { "frintm", AD_INSTR_FRINTM }, + { "frintz", AD_INSTR_FRINTZ }, { "frinta", AD_INSTR_FRINTA }, + /* one blank, idx 13 */ + { NULL, AD_NONE }, + { "frintx", AD_INSTR_FRINTX }, { "frinti", AD_INSTR_FRINTI } + }; + + if(ptype == 0){ + if(OOB(opcode, ptype0_tab)) + return 1; + + tab = ptype0_tab; + } + else if(ptype == 1){ + if(OOB(opcode, ptype1_tab)) + return 1; + + tab = ptype1_tab; + } + else{ + if(OOB(opcode, ptype3_tab)) + return 1; + + tab = ptype3_tab; + } + + instr_s = tab[opcode].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[opcode].instr_id; + + U32 ftype = ptype; + + const char **Rd_Rtbl = NULL; + const char **Rn_Rtbl = NULL; + + U32 Rd_sz = 0; + U32 Rn_sz = 0; + + if(instr_id == AD_INSTR_FCVT){ + U32 opc = bits(i->opcode, 15, 16); + + if(ftype == opc) + return 1; + + if(ftype == 0){ + Rn_Rtbl = AD_RTBL_FP_32; + Rn_sz = _32_BIT; + } + else if(ftype == 1){ + Rn_Rtbl = AD_RTBL_FP_64; + Rn_sz = _64_BIT; + } + else{ + Rn_Rtbl = AD_RTBL_FP_16; + Rn_sz = _16_BIT; + } + + if(opc == 0){ + Rd_Rtbl = AD_RTBL_FP_32; + Rd_sz = _32_BIT; + } + else if(opc == 1){ + Rd_Rtbl = AD_RTBL_FP_64; + Rd_sz = _64_BIT; + } + else{ + Rd_Rtbl = AD_RTBL_FP_16; + Rd_sz = _16_BIT; + } + } + else{ + if(ftype == 0){ + Rd_Rtbl = Rn_Rtbl = AD_RTBL_FP_32; + Rd_sz = Rn_sz = _32_BIT; + } + else if(ftype == 1){ + Rd_Rtbl = Rn_Rtbl = AD_RTBL_FP_64; + Rd_sz = Rn_sz = _64_BIT; + } + else{ + Rd_Rtbl = Rn_Rtbl = AD_RTBL_FP_16; + Rd_sz = Rn_sz = _16_BIT; + } + } + + const char *Rd_s = GET_FP_REG(Rd_Rtbl, Rd); + const char *Rn_s = GET_FP_REG(Rn_Rtbl, Rn); + + ADD_REG_OPERAND(out, Rd, Rd_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rd_Rtbl); + ADD_REG_OPERAND(out, Rn, Rn_sz, NO_PREFER_ZR, _SYSREG(AD_NONE), Rn_Rtbl); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rn_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleFloatingPointCompareInstr(struct instruction *i, + struct ad_insn *out){ + U32 M = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 op = bits(i->opcode, 14, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 opcode2 = bits(i->opcode, 0, 4); + + if(ptype == 2) + return 1; + + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, Rm); + ADD_FIELD(out, op); + ADD_FIELD(out, Rn); + ADD_FIELD(out, opcode2); + + U32 opc = bits(i->opcode, 3, 4); + + S32 signal_all_nans = ((opc >> 1) & 1); + S32 cmp_with_zero = (opc & 1); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(signal_all_nans){ + instr_s = "fcmpe"; + instr_id = AD_INSTR_FCMPE; + } + else{ + instr_s = "fcmp"; + instr_id = AD_INSTR_FCMP; + } + + const char **rtbl = NULL; + U32 sz = 0; + + U32 ftype = ptype; + + if(ftype == 0){ + rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(ftype == 1){ + rtbl = AD_RTBL_FP_64; + sz = _64_BIT; + } + else{ + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + + const char *Rn_s = GET_FP_REG(rtbl, Rn); + + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rn_s); + + if(cmp_with_zero){ + ADD_IMM_OPERAND(out, AD_IMM_FLOAT, 0); + concat(&DECODE_STR(out), ", #0.0"); + } + else{ + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleFloatingPointImmediateInstr(struct instruction *i, + struct ad_insn *out){ + U32 M = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 imm8 = bits(i->opcode, 13, 20); + U32 imm5 = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(M == 1 || S == 1 || ptype == 2 || imm5 != 0) + return 1; + + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, imm8); + ADD_FIELD(out, imm5); + ADD_FIELD(out, Rd); + + const char **rtbl = NULL; + U32 sz = 0; + U32 datasize = 0; + + U32 ftype = ptype; + + if(ftype == 0){ + rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + datasize = 32; + } + else if(ftype == 1){ + rtbl = AD_RTBL_FP_64; + sz = _64_BIT; + datasize = 64; + } + else{ + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + datasize = 16; + } + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + U32 imm = VFPExpandImm(imm8); + + F32 immf = *(F32 *)&imm; + ADD_IMM_OPERAND(out, AD_IMM_FLOAT, imm); + + concat(&DECODE_STR(out), "fmov %s, #%f", Rd_s, immf); + + SET_INSTR_ID(out, AD_INSTR_FMOV); + + return 0; +} + +static S32 DisassembleFloatingPointConditionalCompare(struct instruction *i, + struct ad_insn *out){ + U32 M = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 cond = bits(i->opcode, 12, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 op = bits(i->opcode, 4, 4); + U32 nzcv = bits(i->opcode, 0, 3); + + if(M == 1 || S == 1 || ptype == 2) + return 1; + + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, Rm); + ADD_FIELD(out, cond); + ADD_FIELD(out, Rn); + ADD_FIELD(out, op); + ADD_FIELD(out, nzcv); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(op == 0){ + instr_s = "fccmp"; + instr_id = AD_INSTR_FCCMP; + } + else{ + instr_s = "fccmpe"; + instr_id = AD_INSTR_FCCMPE; + } + + const char **rtbl = NULL; + U32 sz = 0; + + U32 ftype = ptype; + + if(ftype == 0){ + rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(ftype == 1){ + rtbl = AD_RTBL_FP_64; + sz = _64_BIT; + } + else{ + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&nzcv); + + const char *dc = decode_cond(cond); + + concat(&DECODE_STR(out), "%s %s, %s, #%#x, %s", instr_s, Rn_s, Rm_s, nzcv, dc); + + SET_INSTR_ID(out, instr_id); + SET_CC(out, cond); + + return 0; +} + +static S32 DisassembleFloatingPointDataProcessingTwoSourceInstr(struct instruction *i, + struct ad_insn *out){ + U32 M = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 12, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(M == 1 || S == 1 || ptype == 2) + return 1; + + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, Rm); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + { "fmul", AD_INSTR_FMUL }, { "fdiv", AD_INSTR_FDIV }, + { "fadd", AD_INSTR_FADD }, { "fsub", AD_INSTR_FSUB }, + { "fmax", AD_INSTR_FMAX }, { "fmin", AD_INSTR_FMIN }, + { "fmaxnm", AD_INSTR_FMAXNM }, { "fminnm", AD_INSTR_FMINNM }, + { "fnmul", AD_INSTR_FNMUL } + }; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + S32 instr_id = tab[opcode].instr_id; + + const char **rtbl = NULL; + U32 sz = 0; + + U32 ftype = ptype; + + if(ftype == 0){ + rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(ftype == 1){ + rtbl = AD_RTBL_FP_64; + sz = _64_BIT; + } + else{ + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleFloatingPointConditionalSelectInstr(struct instruction *i, + struct ad_insn *out){ + U32 M = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 cond = bits(i->opcode, 12, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(M == 1 || S == 1 || ptype == 2) + return 1; + + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, Rm); + ADD_FIELD(out, cond); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char **rtbl = NULL; + U32 sz = 0; + + U32 ftype = ptype; + + if(ftype == 0){ + rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(ftype == 1){ + rtbl = AD_RTBL_FP_64; + sz = _64_BIT; + } + else{ + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + const char *dc = decode_cond(cond); + + concat(&DECODE_STR(out), "fcsel %s, %s, %s, %s", Rd_s, Rn_s, Rm_s, dc); + + SET_INSTR_ID(out, AD_INSTR_FCSEL); + SET_CC(out, cond); + + return 0; +} + +static S32 DisassembleFloatingPointDataProcessingThreeSourceInstr(struct instruction *i, + struct ad_insn *out){ + U32 M = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 ptype = bits(i->opcode, 22, 23); + U32 o1 = bits(i->opcode, 21, 21); + U32 Rm = bits(i->opcode, 16, 20); + U32 o0 = bits(i->opcode, 15, 15); + U32 Ra = bits(i->opcode, 10, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, ptype); + ADD_FIELD(out, o1); + ADD_FIELD(out, Rm); + ADD_FIELD(out, o0); + ADD_FIELD(out, Ra); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + if(M == 1 || S == 1 || ptype == 2) + return 1; + + struct itab tab[] = { + { "fmadd", AD_INSTR_FMADD }, { "fmsub", AD_INSTR_FMSUB }, + { "fnmadd", AD_INSTR_FNMADD }, { "fnmsub", AD_INSTR_FNMSUB } + }; + + U32 idx = (o1 << 1) | o0; + + if(OOB(idx, tab)) + return 1; + + const char *instr_s = tab[idx].instr_s; + S32 instr_id = tab[idx].instr_id; + + const char **rtbl = NULL; + U32 sz = 0; + + U32 ftype = ptype; + + if(ftype == 0){ + rtbl = AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(ftype == 1){ + rtbl = AD_RTBL_FP_64; + sz = _64_BIT; + } + else{ + rtbl = AD_RTBL_FP_16; + sz = _16_BIT; + } + + const char *Rd_s = GET_FP_REG(rtbl, Rd); + const char *Rn_s = GET_FP_REG(rtbl, Rn); + const char *Rm_s = GET_FP_REG(rtbl, Rm); + const char *Ra_s = GET_FP_REG(rtbl, Ra); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Rm, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + ADD_REG_OPERAND(out, Ra, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), rtbl); + + concat(&DECODE_STR(out), "%s %s, %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s, Ra_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +S32 DataProcessingFloatingPointDisassemble(struct instruction *i, struct ad_insn *out){ + S32 result = 0; + + U32 op0 = bits(i->opcode, 28, 31); + U32 op1 = bits(i->opcode, 23, 24); + U32 op2 = bits(i->opcode, 19, 22); + U32 op3 = bits(i->opcode, 10, 18); + + if(op0 == 4 && (op1 & ~1) == 0 && (op2 & ~8) == 5 && (op3 & ~0x7c) == 2) + result = DisassembleCryptographicAESInstr(i, out); + else if(op0 == 5 && (op1 & ~1) == 0 && (op2 & ~11) == 0 && (op3 & ~0x1dc) == 0) + result = DisassembleCryptographicThreeRegisterSHAInstr(i, out); + else if(op0 == 5 && (op1 & ~1) == 0 && (op2 & ~8) == 5 && (op3 & ~0x7c) == 2) + result = DisassembleCryptographicTwoRegisterSHAInstr(i, out); + else if(((op0 & ~2) == 5 || (op0 & ~6) == 0) && + op1 == 0 && + (op2 & ~3) == 0 && + (op3 & ~0x1de) == 1){ + S32 scalar = (op0 & 1); + result = DisassembleAdvancedSIMDCopyInstr(i, out, scalar); + } + else if(((op0 & ~2) == 5 || (op0 & ~6) == 0) && + (op1 & ~1) == 0 && + ((op2 & ~3) == 8 || (op2 & ~11) == 4 || (op2 & ~11) == 0) && + ((op3 & ~0x1ce) == 1 || (op3 & ~0x1de) == 0x21 || (op3 & ~0x1fe) == 1)){ + S32 scalar = (op0 & 1); + S32 fp16 = (op2 >> 2) == 2 && (op3 & ~0x1ce) == 1; + S32 extra = (op2 & ~11) == 0 && (op3 & ~0x1de) == 0x21; + + result = DisassembleAdvancedSIMDThreeSameInstr(i, out, scalar, fp16, extra); + } + else if(((op0 & ~2) == 5 || (op0 & ~6) == 0) && + (op1 & ~1) == 0 && + ((op2 == 0xf) || (op2 & ~8) == 4) && + (op3 & ~0x7c) == 2){ + S32 scalar = (op0 & 1); + S32 fp16 = (op2 == 0xf); + + result = DisassembleAdvancedSIMDTwoRegisterMiscellaneousInstr(i, out, scalar, fp16); + } + else if((op0 & ~2) == 5 && (op1 & ~1) == 0 && (op2 & ~8) == 6 && (op3 & ~0x7c) == 2) + result = DisassembleAdvancedSIMDScalarPairwiseInstr(i, out); + else if(((op0 & ~2) == 5 || (op0 & ~6) == 0) && + (op1 & ~1) == 0 && + (op2 & ~11) == 4 && + (op3 & ~0x1fc) == 0){ + S32 scalar = (op0 & 1); + result = DisassembleAdvancedSIMDThreeDifferentInstr(i, out, scalar); + } + else if(((op0 & ~2) == 5 || (op0 & ~6) == 0) && + op1 == 2 && + (op3 & ~0x1fe) == 1){ + if(op2 == 0) + result = DisassembleAdvancedSIMDModifiedImmediateInstr(i, out); + else{ + S32 scalar = (op0 & 1); + result = DisassembleAdvancedSIMDShiftByImmediateInstr(i, out, scalar); + } + } + else if(((op0 & ~2) == 5 || (op0 & ~6) == 0) && + (op1 & ~1) == 2 && + (op3 & ~0x1fe) == 0){ + S32 scalar = (op0 & 1); + result = DisassembleAdvancedSIMDXIndexedElementInstr(i, out, scalar); + } + else if((op0 & ~4) == 0 && (op1 & ~1) == 0 && (op2 & ~11) == 0 && (op3 & ~0x1dc) == 0) + result = DisassembleAdvancedSIMDTableLookupInstr(i, out); + else if((op0 & ~4) == 0 && (op1 & ~1) == 0 && (op2 & ~11) == 0 && (op3 & ~0x1dc) == 2) + result = DisassembleAdvancedSIMDPermuteInstr(i, out); + else if((op0 & ~4) == 2 && (op1 & ~1) == 0 && (op2 & ~11) == 0 && (op3 & ~0x1de) == 0) + result = DisassembleAdvancedSIMDExtractInstr(i, out); + else if((op0 & ~6) == 0 && (op1 & ~1) == 0 && (op2 & ~8) == 6 && (op3 & ~0x7c) == 2) + result = DisassembleAdvancedSIMDAcrossLanesInstr(i, out); + else if(op0 == 12 && op1 == 0 && (op2 & ~3) == 8 && (op3 & ~0x1cf) == 0x20) + result = DisassembleCryptographicThreeRegisterImm2Instr(i, out); + else if(op0 == 12 && op1 == 0 && (op2 & ~3) == 12 && (op3 & ~0x1d3) == 0x20) + result = DisassembleCryptographicThreeRegisterSHA512Instr(i, out); + else if(op0 == 12 && op1 == 0 && (op3 & ~0x1df) == 0) + result = DisassembleCryptographicFourRegisterInstr(i, out); + else if(op0 == 12 && op1 == 1 && (op2 & ~3) == 0) + result = DisassembleXARInstr(i, out); + else if(op0 == 12 && op1 == 1 && op2 == 8 && (op3 & ~3) == 0x20) + result = DisassembleCryptographicTwoRegisterSHA512Instr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 0) + result = DisassembleConversionBetweenFloatingPointAndFixedPointInstr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 4 && (op3 & ~0x1c0) == 0) + result = DisassembleConversionBetweenFloatingPointAndIntegerInstr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 4 && (op3 & ~0x1e0) == 0x10) + result = DisassembleFloatingPointDataProcessingOneSourceInstr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 4 && (op3 & ~0x1f0) == 8) + result = DisassembleFloatingPointCompareInstr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 4 && (op3 & ~0x1f8) == 4) + result = DisassembleFloatingPointImmediateInstr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 4 && (op3 & ~0x1fc) == 1) + result = DisassembleFloatingPointConditionalCompare(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 4 && (op3 & ~0x1fc) == 2) + result = DisassembleFloatingPointDataProcessingTwoSourceInstr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 0 && (op2 & ~11) == 4 && (op3 & ~0x1fc) == 3) + result = DisassembleFloatingPointConditionalSelectInstr(i, out); + else if((op0 & ~10) == 1 && (op1 & ~1) == 2) + result = DisassembleFloatingPointDataProcessingThreeSourceInstr(i, out); + else + result = 1; + + return result; +} diff --git a/src/third_party/armadillo/source/DataProcessingFloatingPoint.h b/src/third_party/armadillo/source/DataProcessingFloatingPoint.h new file mode 100644 index 000000000..5f7c45492 --- /dev/null +++ b/src/third_party/armadillo/source/DataProcessingFloatingPoint.h @@ -0,0 +1,7 @@ +#ifndef _DATAPROCESSINGFLOATINGPOINT_H_ +#define _DATAPROCESSINGFLOATINGPOINT_H_ + +S32 DataProcessingFloatingPointDisassemble(struct instruction *i, + struct ad_insn *); + +#endif diff --git a/src/third_party/armadillo/source/DataProcessingImmediate.c b/src/third_party/armadillo/source/DataProcessingImmediate.c new file mode 100644 index 000000000..31b031be5 --- /dev/null +++ b/src/third_party/armadillo/source/DataProcessingImmediate.c @@ -0,0 +1,874 @@ +#include +#include + +#include "adefs.h" +#include "bits.h" +#include "common.h" +#include "instruction.h" +#include "utils.h" +#include "strext.h" + +static S32 DisassemblePCRelativeAddressingInstr(struct instruction *i, + struct ad_insn *out){ + U32 op = bits(i->opcode, 31, 31); + U32 immlo = bits(i->opcode, 29, 30); + U32 immhi = bits(i->opcode, 5, 23); + U32 Rd = bits(i->opcode, 0, 4); + + if(Rd > AD_RTBL_GEN_64_SZ) + return 1; + + ADD_FIELD(out, op); + ADD_FIELD(out, immlo); + ADD_FIELD(out, immhi); + ADD_FIELD(out, Rd); + + U64 imm = 0; + + const char *instr_s = NULL; + + if(op == 0){ + instr_s = "adr"; + + imm = (immhi << 2) | immlo; + imm = sign_extend(imm, 21); + imm += i->PC; + + SET_INSTR_ID(out, AD_INSTR_ADR); + } + else{ + instr_s = "adrp"; + + imm = ((immhi << 2) | immlo) << 12; + imm = sign_extend(imm, 32); + imm += (i->PC & ~0xfff); + + SET_INSTR_ID(out, AD_INSTR_ADRP); + } + + ADD_REG_OPERAND(out, Rd, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + const char *Rd_s = GET_GEN_REG(AD_RTBL_GEN_64, Rd, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, %#lx", instr_s, Rd_s, imm); + + return 0; +} + +static S32 DisassembleAddSubtractImmediateInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 sh = bits(i->opcode, 22, 22); + U32 imm12 = bits(i->opcode, 10, 21); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + const char **registers = AD_RTBL_GEN_32; + U64 len = AD_RTBL_GEN_32_SZ; + + if(sf == 1){ + registers = AD_RTBL_GEN_64; + len = AD_RTBL_GEN_64_SZ; + } + + if(Rn > len || Rd > len) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + ADD_FIELD(out, sh); + ADD_FIELD(out, imm12); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + U64 imm = imm12; + + const char *Rd_s = GET_GEN_REG(registers, Rd, NO_PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, NO_PREFER_ZR); + + S32 instr_id = AD_NONE; + S32 sz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + S32 shift = sh ? 12 : 0; + + if(S == 0 && op == 0){ + if(sh == 0 && imm12 == 0 && (Rd == 0x1f || Rn == 0x1f)){ + instr_id = AD_INSTR_MOV; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + concat(&DECODE_STR(out), "mov %s, %s", Rd_s, Rn_s); + } + else{ + instr_id = AD_INSTR_ADD; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + concat(&DECODE_STR(out), "add %s, %s, #%#lx", Rd_s, Rn_s, imm); + + if(sh){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + } + else if(S == 1 && op == 0){ + if(Rd == 0x1f){ + instr_id = AD_INSTR_CMN; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + concat(&DECODE_STR(out), "cmn %s, #%#lx", Rn_s, imm); + + if(sh){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + else{ + instr_id = AD_INSTR_ADDS; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + concat(&DECODE_STR(out), "adds %s, %s, #%#lx", Rd_s, Rn_s, imm); + + if(sh){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + } + else if(S == 0 && op == 1){ + instr_id = AD_INSTR_SUB; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + concat(&DECODE_STR(out), "sub %s, %s, #%#lx", Rd_s, Rn_s, imm); + + if(sh){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + else if(S == 1 && op == 1){ + if(Rd == 0x1f){ + instr_id = AD_INSTR_CMP; + + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + concat(&DECODE_STR(out), "cmp %s, #%#lx", Rn_s, imm); + + if(sh){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + else{ + instr_id = AD_INSTR_SUBS; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&imm); + + concat(&DECODE_STR(out), "subs %s, %s, #%#lx", Rd_s, Rn_s, imm); + + if(sh){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAddSubtractImmediateWithTagsInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 o2 = bits(i->opcode, 22, 22); + U32 uimm6 = bits(i->opcode, 16, 21); + U32 op3 = bits(i->opcode, 14, 15); + U32 uimm4 = bits(i->opcode, 10, 13); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(sf == 0) + return 1; + + if(sf == 1 && S == 1) + return 1; + + if(Rn > AD_RTBL_GEN_64_SZ || Rd > AD_RTBL_GEN_64_SZ) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + ADD_FIELD(out, o2); + ADD_FIELD(out, uimm6); + ADD_FIELD(out, op3); + ADD_FIELD(out, uimm4); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(op == 0){ + instr_s = "addg"; + instr_id = AD_INSTR_ADDG; + } + else{ + instr_s = "subg"; + instr_id = AD_INSTR_SUBG; + } + + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + const char *Rd_s = GET_GEN_REG(AD_RTBL_GEN_64, Rd, NO_PREFER_ZR); + + uimm6 <<= 4; + + ADD_REG_OPERAND(out, Rd, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&uimm6); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&uimm4); + + concat(&DECODE_STR(out), "%s %s, %s, #%#x, #%#x", instr_s, Rd_s, + Rn_s, uimm6, uimm4); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLogicalImmediateInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 opc = bits(i->opcode, 29, 30); + U32 N = bits(i->opcode, 22, 22); + U32 immr = bits(i->opcode, 16, 21); + U32 imms = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(sf == 0 && N == 1) + return 1; + + U64 imm = 0; + DecodeBitMasks(N, imms, immr, 1, &imm); + + ADD_FIELD(out, sf); + ADD_FIELD(out, opc); + ADD_FIELD(out, N); + ADD_FIELD(out, immr); + ADD_FIELD(out, imms); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char **registers = AD_RTBL_GEN_32; + U64 len = AD_RTBL_GEN_32_SZ; + + if(sf == 1){ + registers = AD_RTBL_GEN_64; + len = AD_RTBL_GEN_64_SZ; + } + + if(Rn > len || Rd > len) + return 1; + + const char *Rn_s = GET_GEN_REG(registers, Rn, NO_PREFER_ZR); + const char *Rd_s = GET_GEN_REG(registers, Rd, NO_PREFER_ZR); + + S32 instr_id = AD_NONE; + S32 sz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + S32 imm_type = sz == _64_BIT ? AD_IMM_LONG : AD_IMM_INT; + + if(opc == 0){ + instr_id = AD_INSTR_AND; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "and %s, %s", Rd_s, Rn_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + else if(opc == 1){ + if(Rn == 0x1f && !MoveWidePreferred(sf, N, imms, immr)){ + instr_id = AD_INSTR_MOV; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "mov %s", Rd_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + else{ + instr_id = AD_INSTR_ORR; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "orr %s, %s", Rd_s, Rn_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + } + else if(opc == 2){ + instr_id = AD_INSTR_EOR; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "eor %s, %s", Rd_s, Rn_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + else if(opc == 3){ + if(Rd == 0x1f){ + instr_id = AD_INSTR_TST; + + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "tst %s", Rn_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + else{ + instr_id = AD_INSTR_ANDS; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "ands %s, %s", Rd_s, Rn_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleMoveWideImmediateInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 opc = bits(i->opcode, 29, 30); + U32 hw = bits(i->opcode, 21, 22); + U32 imm16 = bits(i->opcode, 5, 20); + U32 Rd = bits(i->opcode, 0, 4); + + if(opc == 1) + return 1; + + if(sf == 0 && (hw >> 1) == 1) + return 1; + + const char **registers = AD_RTBL_GEN_32; + U64 len = AD_RTBL_GEN_32_SZ; + + if(sf == 1){ + registers = AD_RTBL_GEN_64; + len = AD_RTBL_GEN_64_SZ; + } + + if(Rd > len) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, opc); + ADD_FIELD(out, hw); + ADD_FIELD(out, imm16); + ADD_FIELD(out, Rd); + + const char *Rd_s = GET_GEN_REG(registers, Rd, NO_PREFER_ZR); + + S32 instr_id = AD_NONE; + S32 sz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + + U32 shift = hw << 4; + + if(opc == 0){ + S32 alias = !(IsZero(imm16) && hw != 0); + + if(sf == 0) + alias = (alias && !IsOnes(imm16, 16)); + + if(alias){ + instr_id = AD_INSTR_MOV; + + S32 imm_type = sz == _64_BIT ? AD_IMM_LONG : AD_IMM_INT; + S64 imm = ~((S64)imm16 << shift); + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "mov %s", Rd_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + else{ + instr_id = AD_INSTR_MOVN; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm16); + + concat(&DECODE_STR(out), "movn %s, #%#x", Rd_s, imm16); + + if(shift != 0){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + } + else if(opc == 2){ + if(!(IsZero(imm16) && hw != 0)){ + instr_id = AD_INSTR_MOV; + + S32 imm_type = sz == _64_BIT ? AD_IMM_LONG : AD_IMM_INT; + S64 imm = (S64)imm16 << shift; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, imm_type, imm_type == AD_IMM_LONG ? *(S64 *)&imm : *(S32 *)&imm); + + concat(&DECODE_STR(out), "mov %s", Rd_s); + + if(imm_type == AD_IMM_LONG) + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(imm)); + else + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm)); + } + else{ + instr_id = AD_INSTR_MOVZ; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_INT, *(U32 *)&imm16); + + concat(&DECODE_STR(out), "movz %s, #%#lx", Rd_s, imm16); + + if(shift != 0){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + } + else if(opc == 3){ + instr_id = AD_INSTR_MOVK; + + ADD_REG_OPERAND(out, Rd, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_INT, *(U32 *)&imm16); + + concat(&DECODE_STR(out), "movk %s, #%#lx", Rd_s, imm16); + + if(shift != 0){ + ADD_SHIFT_OPERAND(out, AD_SHIFT_LSL, shift); + + concat(&DECODE_STR(out), ", lsl #%d", shift); + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleBitfieldInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 opc = bits(i->opcode, 29, 30); + U32 N = bits(i->opcode, 22, 22); + U32 immr = bits(i->opcode, 16, 21); + U32 imms = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(opc == 3) + return 1; + + if(sf == 0 && N == 1) + return 1; + + if(sf == 1 && N == 0) + return 1; + + const char **registers = AD_RTBL_GEN_32; + U64 len = AD_RTBL_GEN_32_SZ; + + if(sf == 1){ + registers = AD_RTBL_GEN_64; + len = AD_RTBL_GEN_64_SZ; + } + + if(Rn > len || Rd > len) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, opc); + ADD_FIELD(out, N); + ADD_FIELD(out, immr); + ADD_FIELD(out, imms); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + + S32 instr_id = AD_NONE; + S32 sz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + + if(opc == 0){ + if((sf == 1 && imms == 0x3f) || (sf == 0 && imms == 0x1f)){ + instr_id = AD_INSTR_ASR; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&immr); + + concat(&DECODE_STR(out), "asr %s, %s, #%#x", Rd_s, Rn_s, immr); + } + else if(imms < immr){ + instr_id = AD_INSTR_SBFIZ; + + U32 lsb = (sz - immr) & (sz - 1); + U32 width = imms + 1; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&lsb); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&width); + + concat(&DECODE_STR(out), "sbfiz %s, %s, #%#x, #%#x", Rd_s, Rn_s, lsb, width); + } + else if(BFXPreferred(sf, (opc >> 1), imms, immr)){ + instr_id = AD_INSTR_SBFX; + + U32 lsb = immr; + U32 width = imms + 1 - lsb; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&lsb); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&width); + + concat(&DECODE_STR(out), "sbfx %s, %s, #%#x, #%#x", Rd_s, Rn_s, lsb, width); + } + else if(immr == 0){ + instr_id = AD_INSTR_SXTB; + const char *instr_s = "sxtb"; + + if(imms == 0xf){ + instr_id = AD_INSTR_SXTH; + instr_s = "sxth"; + } + else if(imms == 0x1f){ + instr_id = AD_INSTR_SXTW; + instr_s = "sxtw"; + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rn_s); + } + else{ + instr_id = AD_INSTR_SBFM; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&immr); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imms); + + concat(&DECODE_STR(out), "sbfm %s, %s, #%#x, #%#x", Rd_s, Rn_s, immr, imms); + } + } + else if(opc == 1){ + if(imms < immr){ + U32 lsb = (sz - immr) & (sz - 1); + U32 width = imms + 1; + + instr_id = AD_INSTR_BFC; + const char *instr_s = "bfc"; + + if(Rn != 0x1f){ + instr_id = AD_INSTR_BFI; + instr_s = "bfi"; + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + /* in this case, BFC will always have the zero register as Rn, so we omit it */ + if(instr_id == AD_INSTR_BFI) + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&lsb); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&width); + + concat(&DECODE_STR(out), "%s %s,", instr_s, Rd_s); + + if(instr_id == AD_INSTR_BFI) + concat(&DECODE_STR(out), " %s,", Rn_s); + + concat(&DECODE_STR(out), " #%#x, #%#x", lsb, width); + } + else if(imms >= immr){ + instr_id = AD_INSTR_BFXIL; + + U32 lsb = immr; + U32 width = imms + 1 - lsb; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&lsb); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&width); + + concat(&DECODE_STR(out), "bfxil %s, %s, #%#x, #%#x", Rd_s, Rn_s, lsb, width); + } + else{ + instr_id = AD_INSTR_BFM; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&immr); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imms); + + concat(&DECODE_STR(out), "bfm %s, %s, #%#x, #%#x", Rd_s, Rn_s, immr, imms); + } + } + else if(opc == 2){ + if(imms + 1 == immr){ + if((sf == 0 && imms != 0x1f) || (sf == 1 && imms != 0x3f)){ + instr_id = AD_INSTR_LSL; + + U32 shift = (sz - 1) - imms; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&shift); + + concat(&DECODE_STR(out), "lsl %s, %s, #%#x", Rd_s, Rn_s, shift); + } + else{ + return 1; + } + } + else if((sf == 0 && imms == 0x1f) || (sf == 1 && imms == 0x3f)){ + instr_id = AD_INSTR_LSR; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&immr); + + concat(&DECODE_STR(out), "lsr %s, %s, #%#x", Rd_s, Rn_s, immr); + } + else if(imms < immr){ + instr_id = AD_INSTR_UBFIZ; + + U32 lsb = sz - immr & (sz - 1); + U32 width = imms + 1; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&lsb); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&width); + + concat(&DECODE_STR(out), "ubfiz %s, %s, #%#x, #%#x", Rd_s, Rn_s, lsb, width); + } + else if(BFXPreferred(sf, (opc >> 1), imms, immr)){ + instr_id = AD_INSTR_UBFX; + + U32 lsb = immr; + U32 width = imms + 1 - lsb; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&lsb); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&width); + + concat(&DECODE_STR(out), "ubfx %s, %s, #%#x, #%#x", Rd_s, Rn_s, lsb, width); + } + else if(immr == 0){ + instr_id = AD_INSTR_UXTB; + const char *instr_s = "uxtb"; + + if(imms == 0xf){ + instr_id = AD_INSTR_UXTH; + instr_s = "uxth"; + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rn_s); + } + else{ + instr_id = AD_INSTR_UBFM; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&immr); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imms); + + concat(&DECODE_STR(out), "ubfm %s, %s, #%#x, #%#x", Rd_s, Rn_s, immr, imms); + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleExtractInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op21 = bits(i->opcode, 29, 30); + U32 N = bits(i->opcode, 22, 22); + U32 o0 = bits(i->opcode, 21, 21); + U32 Rm = bits(i->opcode, 16, 20); + U32 imms = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if((op21 << 1) == 1 || (op21 >> 1) == 1) + return 1; + + if(op21 == 0 && o0 == 1) + return 1; + + if(sf == 0 && ((imms >> 5) == 1 || N == 1)) + return 1; + + if(sf == 1 && N == 0) + return 1; + + const char **registers = AD_RTBL_GEN_32; + U64 len = AD_RTBL_GEN_32_SZ; + + if(sf == 1){ + registers = AD_RTBL_GEN_64; + len = AD_RTBL_GEN_64_SZ; + } + + if(Rm > len || Rn > len || Rd > len) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, op21); + ADD_FIELD(out, N); + ADD_FIELD(out, o0); + ADD_FIELD(out, Rm); + ADD_FIELD(out, imms); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + + S32 instr_id = AD_INSTR_EXTR; + S32 sz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + + const char *instr_s = "extr"; + + if(Rn == Rm){ + instr_id = AD_INSTR_ROR; + instr_s = "ror"; + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + if(Rd != Rm) + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imms); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rn_s); + + if(instr_id == AD_INSTR_EXTR) + concat(&DECODE_STR(out), ", %s", Rm_s); + + concat(&DECODE_STR(out), ", #%#x", imms); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +S32 DataProcessingImmediateDisassemble(struct instruction *i, + struct ad_insn *out){ + U32 op0 = bits(i->opcode, 23, 25); + + S32 result = 0; + + if((op0 >> 1) == 0) + result = DisassemblePCRelativeAddressingInstr(i, out); + else if(op0 == 2) + result = DisassembleAddSubtractImmediateInstr(i, out); + else if(op0 == 3) + result = DisassembleAddSubtractImmediateWithTagsInstr(i, out); + else if(op0 == 4) + result = DisassembleLogicalImmediateInstr(i, out); + else if(op0 == 5) + result = DisassembleMoveWideImmediateInstr(i, out); + else if(op0 == 6) + result = DisassembleBitfieldInstr(i, out); + else if(op0 == 7) + result = DisassembleExtractInstr(i, out); + else + result = 1; + + return result; +} diff --git a/src/third_party/armadillo/source/DataProcessingImmediate.h b/src/third_party/armadillo/source/DataProcessingImmediate.h new file mode 100644 index 000000000..f31b51756 --- /dev/null +++ b/src/third_party/armadillo/source/DataProcessingImmediate.h @@ -0,0 +1,6 @@ +#ifndef _DATAPROCESSINGIMMEDIATE_H_ +#define _DATAPROCESSINGIMMEDIATE_H_ + +S32 DataProcessingImmediateDisassemble(struct instruction *, struct ad_insn *); + +#endif diff --git a/src/third_party/armadillo/source/DataProcessingRegister.c b/src/third_party/armadillo/source/DataProcessingRegister.c new file mode 100644 index 000000000..5d9658d41 --- /dev/null +++ b/src/third_party/armadillo/source/DataProcessingRegister.c @@ -0,0 +1,1064 @@ +#include +#include +#include + +#include "adefs.h" +#include "bits.h" +#include "common.h" +#include "instruction.h" +#include "utils.h" +#include "strext.h" + +#define SHIFTED 0 +#define EXTENDED 1 + +#define REGISTER 0 +#define IMMEDIATE 1 + +static S32 DisassembleDataProcessingTwoSourceInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 Rm = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, sf); + ADD_FIELD(out, S); + ADD_FIELD(out, Rm); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab itab[] = { + { "subp", AD_INSTR_SUBP }, { NULL, AD_NONE }, { "udiv", AD_INSTR_UDIV }, + { "sdiv", AD_INSTR_SDIV }, { "irg", AD_INSTR_IRG }, { "gmi", AD_INSTR_GMI }, + { NULL, AD_NONE }, { NULL, AD_NONE }, { "lslv", AD_INSTR_LSLV }, + { "lsrv", AD_INSTR_LSRV }, { "asrv", AD_INSTR_ASRV }, + { "rorv", AD_INSTR_RORV }, { "pacga", AD_INSTR_PACGA }, + { NULL, AD_NONE }, { NULL, AD_NONE }, { NULL, AD_NONE }, { "crc32b", AD_INSTR_CRC32B }, + { "crc32h", AD_INSTR_CRC32H }, { "crc32w", AD_INSTR_CRC32W }, + { "crc32x", AD_INSTR_CRC32X }, { "crc32cb", AD_INSTR_CRC32CB }, + { "crc32ch", AD_INSTR_CRC32CH }, { "crc32cw", AD_INSTR_CRC32CW }, + { "crc32cx", AD_INSTR_CRC32CX } + }; + + if(OOB(opcode, itab)) + return 1; + + const char *instr_s = itab[opcode].instr_s; + + if(!instr_s) + return 1; + + S32 instr_id = itab[opcode].instr_id; + + if(S == 1 && sf == 1 && opcode == 0){ + instr_s = "subps"; + instr_id = AD_INSTR_SUBPS; + + /* subps --> cmpp */ + if(Rd == 0x1f){ + instr_s = "cmpp"; + instr_id = AD_INSTR_CMPP; + } + } + + SET_INSTR_ID(out, instr_id); + + concat(&DECODE_STR(out), "%s ", instr_s); + + if(strstr(instr_s, "crc")){ + ADD_REG_OPERAND(out, Rd, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_32)); + ADD_REG_OPERAND(out, Rn, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_32)); + + const char *Rd_s = GET_GEN_REG(AD_RTBL_GEN_32, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_32, Rn, PREFER_ZR); + + concat(&DECODE_STR(out), "%s, %s", Rd_s, Rn_s); + + const char *Rm_s = NULL; + + if(sf == 1){ + ADD_REG_OPERAND(out, Rm, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + Rm_s = GET_GEN_REG(AD_RTBL_GEN_64, Rm, PREFER_ZR); + } + else{ + ADD_REG_OPERAND(out, Rm, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_32)); + Rm_s = GET_GEN_REG(AD_RTBL_GEN_32, Rm, PREFER_ZR); + } + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + else if(instr_id == AD_INSTR_UDIV || instr_id == AD_INSTR_SDIV || + instr_id == AD_INSTR_LSLV || instr_id == AD_INSTR_LSRV || + instr_id == AD_INSTR_ASRV || instr_id == AD_INSTR_RORV){ + const char **registers = AD_RTBL_GEN_32; + S32 sz = _32_BIT; + + if(sf == 1){ + registers = AD_RTBL_GEN_64; + sz = _64_BIT; + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), "%s, %s, %s", Rd_s, Rn_s, Rm_s); + } + else{ + if(instr_id != AD_INSTR_CMPP){ + S32 prefer_zr = instr_id != AD_INSTR_IRG; + + ADD_REG_OPERAND(out, Rd, _SZ(_64_BIT), prefer_zr, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + const char *Rd_s = GET_GEN_REG(AD_RTBL_GEN_64, Rd, prefer_zr); + + concat(&DECODE_STR(out), "%s, ", Rd_s); + } + + S32 prefer_zr = instr_id == AD_INSTR_PACGA; + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), prefer_zr, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, prefer_zr); + + concat(&DECODE_STR(out), "%s", Rn_s); + + if(instr_id == AD_INSTR_IRG && Rm == 0x1f) + return 0; + + prefer_zr = (instr_id == AD_INSTR_IRG || instr_id == AD_INSTR_GMI); + + ADD_REG_OPERAND(out, Rm, _SZ(_64_BIT), prefer_zr, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + const char *Rm_s = GET_GEN_REG(AD_RTBL_GEN_64, Rm, prefer_zr); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + + return 0; +} + +static S32 DisassembleDataProcessingOneSourceInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 S = bits(i->opcode, 29, 29); + U32 opcode2 = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, sf); + ADD_FIELD(out, S); + ADD_FIELD(out, opcode2); + ADD_FIELD(out, opcode); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + S32 instr_id = AD_NONE; + + if(opcode2 == 0){ + if(sf == 0 && S == 0 && opcode2 == 0 && opcode == 3) + return 1; + + struct itab tab[] = { + { "rbit", AD_INSTR_RBIT }, { "rev16", AD_INSTR_REV16 }, + { "rev", AD_INSTR_REV }, { "rev32", AD_INSTR_REV32 }, + { "clz", AD_INSTR_CLZ }, { "cls", AD_INSTR_CLS }, + }; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + instr_id = tab[opcode].instr_id; + + if(sf == 1){ + if(opcode == 2){ + instr_s = "rev32"; + instr_id = AD_INSTR_REV32; + } + else if(opcode == 3){ + instr_s = "rev"; + instr_id = AD_INSTR_REV; + } + } + + const char **registers = sf == 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + S32 sz = sf == 1 ? _64_BIT : _32_BIT; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rn_s); + } + else if(opcode2 == 1 && opcode < 8){ + struct itab tab[] = { + { "pacia", AD_INSTR_PACIA }, { "pacib", AD_INSTR_PACIB }, + { "pacda", AD_INSTR_PACDA }, { "pacdb", AD_INSTR_PACDB }, + { "autia", AD_INSTR_AUTIA }, { "autib", AD_INSTR_AUTIB }, + { "autda", AD_INSTR_AUTDA }, { "autdb", AD_INSTR_AUTDB } + }; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + instr_id = tab[opcode].instr_id; + + ADD_REG_OPERAND(out, Rd, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + const char *Rd_s = GET_GEN_REG(AD_RTBL_GEN_64, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rn_s); + } + else if(opcode2 == 1 && opcode >= 8 && Rn == 0x1f){ + struct itab tab[] = { + { "paciza", AD_INSTR_PACIZA }, { "pacizb", AD_INSTR_PACIZB }, + { "pacdza", AD_INSTR_PACDZA }, { "pacdzb", AD_INSTR_PACDZB }, + { "autiza", AD_INSTR_AUTIZA }, { "autizb", AD_INSTR_AUTIZB }, + { "autdza", AD_INSTR_AUTDZA }, { "autdzb", AD_INSTR_AUTDZB }, + { "xpaci", AD_INSTR_XPACI }, { "xpacd", AD_INSTR_XPACD } + }; + + opcode -= 8; + + if(OOB(opcode, tab)) + return 1; + + const char *instr_s = tab[opcode].instr_s; + instr_id = tab[opcode].instr_id; + + ADD_REG_OPERAND(out, Rd, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + const char *Rd_s = GET_GEN_REG(AD_RTBL_GEN_64, Rd, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + } + else{ + return 1; + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static const char *decode_shift(U32 op){ + switch(op){ + case 0: return "lsl"; + case 1: return "lsr"; + case 2: return "asr"; + case 3: return "ror"; + default: return NULL; + }; +} + +static S32 DisassembleLogicalShiftedRegisterInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 opc = bits(i->opcode, 29, 30); + U32 shift = bits(i->opcode, 22, 23); + U32 N = bits(i->opcode, 21, 21); + U32 Rm = bits(i->opcode, 16, 20); + U32 imm6 = bits(i->opcode, 10, 15); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(sf == 0 && (imm6 >> 5) == 1) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, opc); + ADD_FIELD(out, shift); + ADD_FIELD(out, N); + ADD_FIELD(out, Rm); + ADD_FIELD(out, imm6); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char **registers = sf == 0 ? AD_RTBL_GEN_32 : AD_RTBL_GEN_64; + S32 sz = sf == 0 ? _32_BIT : _64_BIT; + + struct itab tab[] = { + { "and", AD_INSTR_AND }, { "bic", AD_INSTR_BIC }, { "orr", AD_INSTR_ORR }, + { "orn", AD_INSTR_ORN }, { "eor", AD_INSTR_EOR }, { "eon", AD_INSTR_EON }, + { "ands", AD_INSTR_ANDS }, { "bics", AD_INSTR_BICS } + }; + + U32 idx = (opc << 1) | N; + + if(OOB(idx, tab)) + return 1; + + const char *instr_s = tab[idx].instr_s; + S32 instr_id = tab[idx].instr_id; + + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + if(instr_id == AD_INSTR_ORR && shift == 0 && imm6 == 0 && Rn == 0x1f){ + instr_s = "mov"; + instr_id = AD_INSTR_MOV; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rm_s); + } + else if(instr_id == AD_INSTR_ORN && Rn == 0x1f){ + instr_s = "mvn"; + instr_id = AD_INSTR_MVN; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rm_s); + } + else if(instr_id == AD_INSTR_ANDS && Rd == 0x1f){ + instr_s = "tst"; + instr_id = AD_INSTR_TST; + + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rn_s, Rm_s); + } + else{ + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + } + + SET_INSTR_ID(out, instr_id); + + U32 amount = imm6; + + /* no need to include , # */ + if(instr_id == AD_INSTR_MOV || amount == 0) + return 0; + + const char *shift_type = decode_shift(shift); + + if(!shift_type) + return 1; + + ADD_SHIFT_OPERAND(out, shift, amount); + + concat(&DECODE_STR(out), ", %s #"S_X"", shift_type, S_A(amount)); + + return 0; +} + +static S32 get_extended_Rm(U32 option, char **regstr, U32 Rm, + U32 *sz, const char ***registers){ + S32 _64_bit = (option & ~4) == 3; + + if(_64_bit) + concat(regstr, "x"); + else + concat(regstr, "w"); + + if(Rm == 0x1f) + concat(regstr, "zr"); + else + concat(regstr, "%d", Rm); + + *sz = _64_bit ? _64_BIT : _32_BIT; + *registers = _64_bit ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + + return _64_bit; +} + +static char *get_extended_extend_string(U32 option, U32 sf, + U32 Rd, U32 Rn, U32 imm3){ + char *extend_string = NULL; + const char *extend = decode_reg_extend(option); + + S32 is_lsl = 0; + + if(Rd == 0x1f || Rn == 0x1f){ + if((sf == 0 && option == 2) || (sf == 1 && option == 3)){ + if(imm3 == 0) + extend = ""; + else{ + extend = "lsl"; + is_lsl = 1; + } + } + } + + U32 amount = imm3; + + if(*extend) + concat(&extend_string, "%s", extend); + + if(is_lsl || (!is_lsl && amount != 0)) + concat(&extend_string, " #"S_X"", S_A(amount)); + + return extend_string; +} + +static S32 DisassembleAddSubtractShiftedOrExtendedInstr(struct instruction *i, + struct ad_insn *out, S32 kind){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 shift = bits(i->opcode, 22, 23); + U32 opt = shift; + U32 Rm = bits(i->opcode, 16, 20); + U32 option = bits(i->opcode, 13, 15); + U32 imm3 = bits(i->opcode, 10, 12); + U32 imm6 = (option << 3) | imm3; + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + + if(kind == SHIFTED) + ADD_FIELD(out, shift); + else + ADD_FIELD(out, opt); + + ADD_FIELD(out, Rm); + + if(kind == SHIFTED) + ADD_FIELD(out, imm6); + else{ + ADD_FIELD(out, option); + ADD_FIELD(out, imm3); + } + + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + { "add", AD_INSTR_ADD }, { "adds", AD_INSTR_ADDS }, + { "sub", AD_INSTR_SUB }, { "subs", AD_INSTR_SUBS } + }; + + U32 idx = (op << 1) | S; + + if(OOB(idx, tab)) + return 1; + + const char *instr_s = tab[idx].instr_s; + S32 instr_id = tab[idx].instr_id; + + S32 prefer_zr_Rd_Rn = kind == SHIFTED; + + const char **registers = sf == 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + S32 sz = sf == 1 ? _64_BIT : _32_BIT; + + /* Both shifted and extended have aliases for ADDS and SUBS, + * but only shifted has aliases for SUB. + */ + if((instr_id == AD_INSTR_ADDS || instr_id == AD_INSTR_SUBS) && Rd == 0x1f){ + if(instr_id == AD_INSTR_ADDS){ + instr_s = "cmn"; + instr_id = AD_INSTR_CMN; + } + else if(instr_id == AD_INSTR_SUBS){ + instr_s = "cmp"; + instr_id = AD_INSTR_CMP; + } + + ADD_REG_OPERAND(out, Rn, sz, prefer_zr_Rd_Rn, _SYSREG(AD_NONE), + _RTBL(registers)); + const char *Rn_s = GET_GEN_REG(registers, Rn, prefer_zr_Rd_Rn); + + char *Rm_s = NULL; + + if(kind == SHIFTED || (kind == EXTENDED && sf == 0)){ + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(registers)); + Rm_s = (char *)GET_GEN_REG(registers, Rm, PREFER_ZR); + } + else{ + U32 sz = 0; + const char **registers = NULL; + S32 _64_bit = get_extended_Rm(option, &Rm_s, Rm, &sz, ®isters); + + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + } + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rn_s, Rm_s); + + if(kind == EXTENDED && sf == 1) + free(Rm_s); + } + else if((instr_id == AD_INSTR_SUB || instr_id == AD_INSTR_SUBS) && + Rn == 0x1f && kind == SHIFTED){ + if(instr_id == AD_INSTR_SUB){ + instr_s = "neg"; + instr_id = AD_INSTR_NEG; + } + else if(instr_id == AD_INSTR_SUBS){ + instr_s = "negs"; + instr_id = AD_INSTR_NEGS; + } + + ADD_REG_OPERAND(out, Rd, sz, prefer_zr_Rd_Rn, _SYSREG(AD_NONE), + _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(registers)); + + const char *Rd_s = GET_GEN_REG(registers, Rd, prefer_zr_Rd_Rn); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, %s", instr_s, Rd_s, Rm_s); + } + else{ + ADD_REG_OPERAND(out, Rd, sz, prefer_zr_Rd_Rn, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, prefer_zr_Rd_Rn, _SYSREG(AD_NONE), _RTBL(registers)); + + const char *Rd_s = GET_GEN_REG(registers, Rd, prefer_zr_Rd_Rn); + const char *Rn_s = GET_GEN_REG(registers, Rn, prefer_zr_Rd_Rn); + + char *Rm_s = NULL; + + if(kind == SHIFTED || (kind == EXTENDED && sf == 0)){ + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(registers)); + Rm_s = (char *)GET_GEN_REG(registers, Rm, PREFER_ZR); + } + else{ + U32 sz = 0; + const char **registers = NULL; + S32 _64_bit = get_extended_Rm(option, &Rm_s, Rm, &sz, ®isters); + + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + } + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + + if(kind == EXTENDED && sf == 1) + free(Rm_s); + } + + if(kind == SHIFTED){ + if(shift == 3) + return 1; + + const char *shift_type = decode_shift(shift); + + U32 amount = imm6; + + if(amount != 0){ + ADD_SHIFT_OPERAND(out, shift, amount); + + concat(&DECODE_STR(out), ", %s #"S_X"", shift_type, S_A(amount)); + } + } + else{ + char *extend_string = get_extended_extend_string(option, sf, Rd, Rn, imm3); + + if(extend_string) + concat(&DECODE_STR(out), ", %s", extend_string); + + free(extend_string); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleAddSubtractCarryInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 Rm = bits(i->opcode, 16, 20); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + ADD_FIELD(out, Rm); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char **registers = sf == 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + S32 sz = sf == 1 ? _64_BIT : _32_BIT; + + struct itab tab[] = { + { "adc", AD_INSTR_ADC }, { "adcs", AD_INSTR_ADCS }, + { "sbc", AD_INSTR_SBC }, { "sbcs", AD_INSTR_SBCS } + }; + + U32 idx = (op << 1) | sf; + + if(OOB(idx, tab)) + return 1; + + const char *instr_s = tab[idx].instr_s; + S32 instr_id = tab[idx].instr_id; + + if(instr_id == AD_INSTR_SBC && Rn == 0x1f){ + instr_s = "ngc"; + instr_id = AD_INSTR_NGC; + } + else if(instr_id == AD_INSTR_SBCS && Rn == 0x1f){ + instr_s = "ngcs"; + instr_id = AD_INSTR_NGCS; + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + if(instr_id != AD_INSTR_NGC && instr_id != AD_INSTR_NGCS) + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, ", instr_s, Rd_s); + + if(instr_id != AD_INSTR_NGC && instr_id != AD_INSTR_NGCS) + concat(&DECODE_STR(out), "%s, ", Rn_s); + + concat(&DECODE_STR(out), "%s", Rm_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleRotateRightIntoFlagsInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 imm6 = bits(i->opcode, 15, 20); + U32 Rn = bits(i->opcode, 5, 9); + U32 o2 = bits(i->opcode, 4, 4); + U32 mask = bits(i->opcode, 0, 3); + + if(sf != 1 && op != 0 && S != 1 && o2 != 0) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + ADD_FIELD(out, imm6); + ADD_FIELD(out, Rn); + ADD_FIELD(out, o2); + ADD_FIELD(out, mask); + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm6); + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&mask); + + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, PREFER_ZR); + + concat(&DECODE_STR(out), "rmif %s, #"S_X", #"S_X"", Rn_s, S_A(imm6), S_A(mask)); + + SET_INSTR_ID(out, AD_INSTR_RMIF); + + return 0; +} + +static S32 DisassembleEvaluateIntoFlagsInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 opcode2 = bits(i->opcode, 15, 20); + U32 sz = bits(i->opcode, 14, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 o3 = bits(i->opcode, 4, 4); + U32 mask = bits(i->opcode, 0, 3); + + if(sf != 0 && op != 0 && S != 1 && opcode2 != 0 && o3 != 0 && mask != 13) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + ADD_FIELD(out, opcode2); + ADD_FIELD(out, sz); + ADD_FIELD(out, Rn); + ADD_FIELD(out, o3); + ADD_FIELD(out, mask); + + S32 instr_id = sz == 0 ? AD_INSTR_SETF8 : AD_INSTR_SETF16; + + ADD_REG_OPERAND(out, Rn, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_32)); + + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_32, Rn, PREFER_ZR); + + concat(&DECODE_STR(out), "setf%d %s", sz == 0 ? 8 : 16, Rn_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleConditionalCompareInstr(struct instruction *i, + struct ad_insn *out, S32 kind){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 Rm = bits(i->opcode, 16, 20); + U32 imm5 = Rm; + U32 cond = bits(i->opcode, 12, 15); + U32 o2 = bits(i->opcode, 10, 10); + U32 Rn = bits(i->opcode, 5, 9); + U32 o3 = bits(i->opcode, 4, 4); + U32 nzcv = bits(i->opcode, 0, 3); + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + + if(kind == REGISTER) + ADD_FIELD(out, Rm); + else + ADD_FIELD(out, imm5); + + ADD_FIELD(out, cond); + ADD_FIELD(out, o2); + ADD_FIELD(out, Rn); + ADD_FIELD(out, o3); + ADD_FIELD(out, nzcv); + + struct itab tab[] = { + { "ccmn", AD_INSTR_CCMN }, { "ccmp", AD_INSTR_CCMP } + }; + + U32 idx = op; + + if(OOB(idx, tab)) + return 1; + + const char *instr_s = tab[idx].instr_s; + S32 instr_id = tab[idx].instr_id; + + const char **registers = sf == 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + S32 sz = sf == 1 ? _64_BIT : _32_BIT; + + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rn_s); + + if(kind == REGISTER){ + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + else{ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm5); + concat(&DECODE_STR(out), ", #"S_X"", S_A(imm5)); + } + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&nzcv); + concat(&DECODE_STR(out), ", #"S_X"", S_A(nzcv)); + + const char *cond_s = decode_cond(cond); + + if(!cond_s) + return 1; + + concat(&DECODE_STR(out), ", %s", cond_s); + + SET_CC(out, cond); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleConditionalSelectInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op = bits(i->opcode, 30, 30); + U32 S = bits(i->opcode, 29, 29); + U32 Rm = bits(i->opcode, 16, 20); + U32 cond = bits(i->opcode, 12, 15); + U32 op2 = bits(i->opcode, 10, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + if(S == 1) + return 1; + + ADD_FIELD(out, sf); + ADD_FIELD(out, op); + ADD_FIELD(out, S); + ADD_FIELD(out, Rm); + ADD_FIELD(out, cond); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + struct itab tab[] = { + { "csel", AD_INSTR_CSEL }, { "csinc", AD_INSTR_CSINC }, + { "csinv", AD_INSTR_CSINV }, { "csneg", AD_INSTR_CSNEG } + }; + + U32 idx = (op << 1) | (op2 & 1); + + if(OOB(idx, tab)) + return 1; + + const char **registers = sf == 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + S32 sz = sf == 1 ? _64_BIT : _32_BIT; + + const char *instr_s = tab[idx].instr_s; + S32 instr_id = tab[idx].instr_id; + + if(instr_id == AD_INSTR_CSINC || instr_id == AD_INSTR_CSINV){ + if(Rm != 0x1f && (cond >> 1) != 7 && Rn != 0x1f && Rn == Rm){ + instr_s = instr_id == AD_INSTR_CSINC ? "cinc" : "cinv"; + instr_id = instr_id == AD_INSTR_CSINC ? AD_INSTR_CINC : AD_INSTR_CINV; + } + else if(Rm == 0x1f && (cond >> 1) != 7 && Rn == 0x1f){ + instr_s = instr_id == AD_INSTR_CSINC ? "cset" : "csetm"; + instr_id = instr_id == AD_INSTR_CSINC ? AD_INSTR_CSET : AD_INSTR_CSETM; + } + } + else if(instr_id == AD_INSTR_CSNEG){ + if((cond >> 1) != 7 && Rn == Rm){ + instr_s = "cneg"; + instr_id = AD_INSTR_CNEG; + } + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rd_s); + + if(instr_id != AD_INSTR_CSET && instr_id != AD_INSTR_CSETM){ + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rn_s); + } + + if(instr_id != AD_INSTR_CINC && instr_id != AD_INSTR_CSET && + instr_id != AD_INSTR_CINV && instr_id != AD_INSTR_CSETM && + instr_id != AD_INSTR_CNEG){ + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + else{ + /* for the aliases, LSB of cond is inverted */ + cond &= ~1; + } + + const char *cond_s = decode_cond(cond); + + if(!cond_s) + return 1; + + concat(&DECODE_STR(out), ", %s", cond_s); + + SET_CC(out, cond); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleDataProcessingThreeSourceInstr(struct instruction *i, + struct ad_insn *out){ + U32 sf = bits(i->opcode, 31, 31); + U32 op54 = bits(i->opcode, 29, 30); + U32 op31 = bits(i->opcode, 21, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 o0 = bits(i->opcode, 15, 15); + U32 Ra = bits(i->opcode, 10, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rd = bits(i->opcode, 0, 4); + + ADD_FIELD(out, sf); + ADD_FIELD(out, op54); + ADD_FIELD(out, op31); + ADD_FIELD(out, Rm); + ADD_FIELD(out, o0); + ADD_FIELD(out, Ra); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rd); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(op31 == 0){ + const char **registers = sf == 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + S32 sz = sf == 1 ? _64_BIT : _32_BIT; + + struct itab tab[] = { + { "madd", AD_INSTR_MADD }, { "msub", AD_INSTR_MSUB } + }; + + instr_s = tab[o0].instr_s; + instr_id = tab[o0].instr_id; + + if(instr_id == AD_INSTR_MADD && Ra == 0x1f){ + instr_s = "mul"; + instr_id = AD_INSTR_MUL; + } + else if(instr_id == AD_INSTR_MSUB && Ra == 0x1f){ + instr_s = "mneg"; + instr_id = AD_INSTR_MNEG; + } + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + + if(instr_id != AD_INSTR_MUL && instr_id != AD_INSTR_MNEG){ + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + const char *Ra_s = GET_GEN_REG(registers, Ra, PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Ra_s); + } + } + else if(op31 == 2 || op31 == 6){ + const char **registers = sf == 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32; + S32 sz = sf == 1 ? _64_BIT : _32_BIT; + + instr_s = op31 == 2 ? "smulh" : "umulh"; + instr_id = op31 == 2 ? AD_INSTR_SMULH : AD_INSTR_UMULH; + + ADD_REG_OPERAND(out, Rd, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rn, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rm, sz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + const char *Rd_s = GET_GEN_REG(registers, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(registers, Rn, PREFER_ZR); + const char *Rm_s = GET_GEN_REG(registers, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + } + else if(op31 == 1 || op31 == 5){ + if(op31 == 1){ + instr_s = o0 == 0 ? "smaddl" : "smsubl"; + instr_id = o0 == 0 ? AD_INSTR_SMADDL : AD_INSTR_SMSUBL; + } + else{ + instr_s = o0 == 0 ? "umaddl" : "umsubl"; + instr_id = o0 == 0 ? AD_INSTR_UMADDL : AD_INSTR_UMSUBL; + } + + if(Ra == 0x1f){ + if(instr_id == AD_INSTR_SMADDL){ + instr_s = "smull"; + instr_id = AD_INSTR_SMULL; + } + else if(instr_id == AD_INSTR_SMSUBL){ + instr_s = "smnegl"; + instr_id = AD_INSTR_SMNEGL; + } + else if(instr_id == AD_INSTR_UMADDL){ + instr_s = "umull"; + instr_id = AD_INSTR_UMULL; + } + else if(instr_id == AD_INSTR_UMSUBL){ + instr_s = "umnegl"; + instr_id = AD_INSTR_UMNEGL; + } + } + + ADD_REG_OPERAND(out, Rd, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rn, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_32)); + ADD_REG_OPERAND(out, Rm, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_32)); + + const char *Rd_s = GET_GEN_REG(AD_RTBL_GEN_64, Rd, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_32, Rn, PREFER_ZR); + const char *Rm_s = GET_GEN_REG(AD_RTBL_GEN_32, Rm, PREFER_ZR); + + concat(&DECODE_STR(out), "%s %s, %s, %s", instr_s, Rd_s, Rn_s, Rm_s); + + if(instr_id != AD_INSTR_SMULL && instr_id != AD_INSTR_SMNEGL && + instr_id != AD_INSTR_UMULL && instr_id != AD_INSTR_UMNEGL){ + ADD_REG_OPERAND(out, Ra, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + const char *Ra_s = GET_GEN_REG(AD_RTBL_GEN_64, Ra, PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Ra_s); + } + } + + if(!instr_s) + return 1; + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +S32 DataProcessingRegisterDisassemble(struct instruction *i, + struct ad_insn *out){ + S32 result = 0; + + U32 op0 = bits(i->opcode, 30, 30); + U32 op1 = bits(i->opcode, 28, 28); + U32 op2 = bits(i->opcode, 21, 24); + U32 op3 = bits(i->opcode, 10, 15); + + if(op0 == 0 && op1 == 1 && op2 == 6) + result = DisassembleDataProcessingTwoSourceInstr(i, out); + else if(op0 == 1 && op1 == 1 && op2 == 6) + result = DisassembleDataProcessingOneSourceInstr(i, out); + else if(op1 == 0 && (op2 & ~7) == 0) + result = DisassembleLogicalShiftedRegisterInstr(i, out); + else if(op1 == 0 && ((op2 & ~6) == 8 || (op2 & ~6) == 9)) + result = DisassembleAddSubtractShiftedOrExtendedInstr(i, out, op2 & 1); + else if(op1 == 1 && op2 == 0 && op3 == 0) + result = DisassembleAddSubtractCarryInstr(i, out); + else if(op1 == 1 && op2 == 0 && (op3 & ~0x20) == 1) + result = DisassembleRotateRightIntoFlagsInstr(i, out); + else if(op1 == 1 && op2 == 0 && (op3 & ~0x30) == 2) + result = DisassembleEvaluateIntoFlagsInstr(i, out); + else if(op1 == 1 && op2 == 2 && ((op3 & ~0x3d) == 0 || (op3 & ~0x3d) == 2)) + result = DisassembleConditionalCompareInstr(i, out, op3 & ~0x3d); + else if(op1 == 1 && op2 == 4) + result = DisassembleConditionalSelectInstr(i, out); + else if(op1 == 1 && (op2 >> 3) == 1) + result = DisassembleDataProcessingThreeSourceInstr(i, out); + else + result = 1; + + return result; +} diff --git a/src/third_party/armadillo/source/DataProcessingRegister.h b/src/third_party/armadillo/source/DataProcessingRegister.h new file mode 100644 index 000000000..edfea7dce --- /dev/null +++ b/src/third_party/armadillo/source/DataProcessingRegister.h @@ -0,0 +1,6 @@ +#ifndef _DATAPROCESSINGREGISTER_H_ +#define _DATAPROCESSINGREGISTER_H_ + +S32 DataProcessingRegisterDisassemble(struct instruction *, struct ad_insn *); + +#endif diff --git a/src/third_party/armadillo/source/LoadsAndStores.c b/src/third_party/armadillo/source/LoadsAndStores.c new file mode 100644 index 000000000..57fba0eea --- /dev/null +++ b/src/third_party/armadillo/source/LoadsAndStores.c @@ -0,0 +1,2829 @@ +#include +#include + +#include "adefs.h" +#include "bits.h" +#include "common.h" +#include "instruction.h" +#include "utils.h" +#include "strext.h" + +#define NO_ALLOCATE 0 +#define POST_INDEXED 1 +#define OFFSET 2 +#define PRE_INDEXED 3 + +#define UNSIGNED_IMMEDIATE -1 + +#define UNSCALED_IMMEDIATE 0 +#define IMMEDIATE_POST_INDEXED 1 +#define UNPRIVILEGED 2 +#define IMMEDIATE_PRE_INDEXED 3 + +#define AD_NONE_C2099_MSVC -1 +static struct itab unscaled_instr_tbl[] = { + { "sturb", AD_INSTR_STURB }, + { "ldurb", AD_INSTR_LDURB }, + { "ldursb", AD_INSTR_LDURSB }, + { "ldursb", AD_INSTR_LDURSB }, + { "stur", AD_INSTR_STUR }, + { "ldur", AD_INSTR_LDUR }, + { "stur", AD_INSTR_STUR }, + { "ldur", AD_INSTR_LDUR }, + { "sturh", AD_INSTR_STURH }, + { "ldurh", AD_INSTR_LDURH }, + { "ldursh", AD_INSTR_LDURSH }, + { "ldursh", AD_INSTR_LDURSH }, + { "stur", AD_INSTR_STUR }, + { "ldur", AD_INSTR_LDUR }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { "stur", AD_INSTR_STUR }, + { "ldur", AD_INSTR_LDUR }, + { "ldursw", AD_INSTR_LDURSW }, + { NULL, AD_NONE_C2099_MSVC }, + { "stur", AD_INSTR_STUR }, + { "ldur", AD_INSTR_LDUR }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { "stur", AD_INSTR_STUR }, + { "ldur", AD_INSTR_LDUR }, + { "prfum", AD_INSTR_PRFUM }, + { NULL, AD_NONE_C2099_MSVC }, + { "stur", AD_INSTR_STUR }, + { "ldur", AD_INSTR_LDUR } +}; + +static struct itab pre_post_unsigned_register_idx_instr_tbl[] = { + { "strb", AD_INSTR_STRB }, + { "ldrb", AD_INSTR_LDRB }, + { "ldrsb", AD_INSTR_LDRSB }, + { "ldrsb", AD_INSTR_LDRSB }, + { "str", AD_INSTR_STR }, + { "ldr", AD_INSTR_LDR }, + { "str", AD_INSTR_STR }, + { "ldr", AD_INSTR_LDR }, + { "strh", AD_INSTR_STRH }, + { "ldrh", AD_INSTR_LDRH }, + { "ldrsh", AD_INSTR_LDRSH }, + { "ldrsh", AD_INSTR_LDRSH }, + { "str", AD_INSTR_STR }, + { "ldr", AD_INSTR_LDR }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { "str", AD_INSTR_STR }, + { "ldr", AD_INSTR_LDR }, + { "ldrsw", AD_INSTR_LDRSW }, + { NULL, AD_NONE_C2099_MSVC }, + { "str", AD_INSTR_STR }, + { "ldr", AD_INSTR_LDR }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { "str", AD_INSTR_STR }, + { "ldr", AD_INSTR_LDR }, + { "prfm", AD_INSTR_PRFM }, + { NULL, AD_NONE_C2099_MSVC }, + { "str", AD_INSTR_STR }, + { "ldr", AD_INSTR_LDR } +}; + +static struct itab unprivileged_instr_tbl[] = { + { "sttrb", AD_INSTR_STTRB }, + { "ldtrb", AD_INSTR_LDTRB }, + { "ldtrsb", AD_INSTR_LDTRSB }, + { "ldtrsb", AD_INSTR_LDTRSB }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { "sttrh", AD_INSTR_STTRH }, + { "ldtrh", AD_INSTR_LDTRH }, + { "ldtrsh", AD_INSTR_LDTRSH }, + { "ldtrsh", AD_INSTR_LDTRSH }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { "sttr", AD_INSTR_STTR }, + { "ldtr", AD_INSTR_LDTR }, + { "ldtrsw", AD_INSTR_LDTRSW }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { NULL, AD_NONE_C2099_MSVC }, + { "sttr", AD_INSTR_STTR }, + { "ldtr", AD_INSTR_LDTR }, + { NULL, AD_NONE_C2099_MSVC } +}; + +static S32 get_post_idx_immediate_offset(S32 regamount, U32 Q){ + if(regamount == 1) + return Q == 0 ? 8 : 16; + if(regamount == 2) + return Q == 0 ? 16 : 32; + if(regamount == 3) + return Q == 0 ? 24 : 48; + if(regamount == 4) + return Q == 0 ? 32 : 64; + + return -1; +} + +static S32 DisassembleLoadStoreMultStructuresInstr(struct instruction *i, + struct ad_insn *out, S32 postidxed){ + U32 Q = bits(i->opcode, 30, 30); + U32 L = bits(i->opcode, 22, 22); + U32 Rm = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 12, 15); + U32 size = bits(i->opcode, 10, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + const char *T = get_arrangement(size, Q); + + if(!T) + return 1; + + ADD_FIELD(out, Q); + ADD_FIELD(out, L); + + if(postidxed) + ADD_FIELD(out, Rm); + + ADD_FIELD(out, opcode); + ADD_FIELD(out, size); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(L == 0) + instr_s = "st"; + else + instr_s = "ld"; + + U32 regcnt, selem; + + switch(opcode){ + case 0: regcnt = 4; selem = 4; break; + case 0x2: regcnt = 4; selem = 1; break; + case 0x4: regcnt = 3; selem = 3; break; + case 0x6: regcnt = 3; selem = 1; break; + case 0x7: regcnt = 1; selem = 1; break; + case 0x8: regcnt = 2; selem = 2; break; + case 0xa: regcnt = 2; selem = 1; break; + default: return 1; + }; + + if(L == 0) + instr_id = (AD_INSTR_ST1 - 1) + selem; + else + /* the way the AD_INSTR_* enum is set up makes this more complicated */ + instr_id = (AD_INSTR_LD1 - 1) + ((selem * 2) - 1); + + concat(&DECODE_STR(out), "%s%d { ", instr_s, selem); + + for(S32 i=Rt; i<(Rt+regcnt)-1; i++){ + ADD_REG_OPERAND(out, i, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_FP_V_128)); + const char *Ri_s = GET_FP_REG(AD_RTBL_FP_V_128, i); + + concat(&DECODE_STR(out), "%s.%s, ", Ri_s, T); + } + + ADD_REG_OPERAND(out, (Rt+regcnt)-1, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_V_128)); + const char *last_Rt_s = GET_FP_REG(AD_RTBL_FP_V_128, (Rt+regcnt)-1); + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "%s.%s }, [%s]", last_Rt_s, T, Rn_s); + + if(postidxed){ + if(Rm != 0x1f){ + ADD_REG_OPERAND(out, Rm, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + const char *Rm_s = GET_GEN_REG(AD_RTBL_GEN_64, Rm, NO_PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + else{ + S32 imm = get_post_idx_immediate_offset(regcnt, Q); + + if(imm == -1) + return 1; + + /* imm is unsigned, that fxn returns -1 for error checking */ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm); + + concat(&DECODE_STR(out), ", #%#x", (U32)imm); + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLoadStoreSingleStructuresInstr(struct instruction *i, + struct ad_insn *out, S32 postidxed){ + U32 Q = bits(i->opcode, 30, 30); + U32 L = bits(i->opcode, 22, 22); + U32 R = bits(i->opcode, 21, 21); + U32 Rm = bits(i->opcode, 16, 20); + U32 opcode = bits(i->opcode, 13, 15); + U32 S = bits(i->opcode, 12, 12); + U32 size = bits(i->opcode, 10, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + ADD_FIELD(out, Q); + ADD_FIELD(out, L); + ADD_FIELD(out, R); + + if(postidxed) + ADD_FIELD(out, Rm); + + ADD_FIELD(out, opcode); + ADD_FIELD(out, S); + ADD_FIELD(out, size); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + if(L == 0) + instr_s = "st"; + else + instr_s = "ld"; + + const char *suffix = NULL; + + U32 scale = opcode >> 1; + U32 selem = (((opcode & 1) << 1) | R) + 1; + U32 index = 0; + + S32 replicate = 0; + + switch(scale){ + case 3: replicate = 1; break; + case 0: + { + index = (Q << 3) | (S << 2) | size; + suffix = "b"; + break; + } + case 1: + { + index = (Q << 2) | (S << 1) | (size >> 1); + suffix = "h"; + break; + } + case 2: + { + if((size & 1) == 0){ + index = (Q << 1) | S; + suffix = "s"; + } + else{ + index = Q; + suffix = "d"; + } + + break; + } + default: return 1; + }; + + if(replicate) + instr_id = (AD_INSTR_LD1R - 1) + ((selem * 2) - 1); + else if(L == 0) + instr_id = (AD_INSTR_ST1 - 1) + selem; + else if(L == 1) + instr_id = (AD_INSTR_LD1 - 1) + ((selem * 2) - 1); + + concat(&DECODE_STR(out), "%s%d%s { ", instr_s, selem, replicate ? "r" : ""); + + for(S32 i=Rt; i<(Rt+selem)-1; i++){ + ADD_REG_OPERAND(out, i, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_V_128)); + const char *Ri_s = GET_FP_REG(AD_RTBL_FP_V_128, i); + + concat(&DECODE_STR(out), "%s", Ri_s); + + if(replicate){ + const char *T = get_arrangement(size, Q); + + if(!T) + return 1; + + concat(&DECODE_STR(out), ".%s", T); + } + else{ + concat(&DECODE_STR(out), ".%s", suffix); + } + + concat(&DECODE_STR(out), ", "); + } + + ADD_REG_OPERAND(out, (Rt+selem)-1, _SZ(_128_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_FP_V_128)); + const char *last_Rt_s = GET_FP_REG(AD_RTBL_FP_V_128, (Rt+selem)-1); + + concat(&DECODE_STR(out), "%s", last_Rt_s); + + if(replicate){ + const char *T = get_arrangement(size, Q); + + if(!T) + return 1; + + concat(&DECODE_STR(out), ".%s", T); + } + else{ + concat(&DECODE_STR(out), ".%s", suffix); + } + + concat(&DECODE_STR(out), " }"); + + if(!replicate){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&index); + concat(&DECODE_STR(out), "[%d]", index); + } + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), _RTBL(AD_RTBL_GEN_64)); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + concat(&DECODE_STR(out), ", [%s]", Rn_s); + + S32 rimms[] = { 1, 2, 4, 8 }; + + if(postidxed){ + if(replicate){ + if(Rm != 0x1f){ + ADD_REG_OPERAND(out, Rm, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + const char *Rm_s = GET_GEN_REG(AD_RTBL_GEN_64, Rm, NO_PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + else{ + U32 imm = rimms[size] * selem; + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm); + + concat(&DECODE_STR(out), ", #%#x", imm); + } + } + else{ + if(Rm != 0x1f){ + ADD_REG_OPERAND(out, Rm, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + const char *Rm_s = GET_GEN_REG(AD_RTBL_GEN_64, Rm, NO_PREFER_ZR); + + concat(&DECODE_STR(out), ", %s", Rm_s); + } + else{ + S32 idx = 0; + + if(*suffix == 'h') + idx = 1; + else if(*suffix == 's') + idx = 2; + else if(*suffix == 'd') + idx = 3; + + U32 imm = rimms[idx] * selem; + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm); + + concat(&DECODE_STR(out), ", #%#x", imm); + } + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLoadStoreMemoryTagsInstr(struct instruction *i, + struct ad_insn *out){ + U32 opc = bits(i->opcode, 22, 23); + U32 imm9 = bits(i->opcode, 12, 20); + U32 op2 = bits(i->opcode, 10, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + if((opc == 2 || opc == 3) && imm9 != 0 && op2 == 0) + return 1; + + ADD_FIELD(out, opc); + ADD_FIELD(out, imm9); + ADD_FIELD(out, op2); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + + if((opc == 0 || opc == 2 || opc == 3) && imm9 == 0 && op2 == 0){ + const char *instr_s = NULL; + + if(opc == 0){ + instr_s = "stzgm"; + instr_id = AD_INSTR_STZGM; + } + else if(opc == 2){ + instr_s = "stgm"; + instr_id = AD_INSTR_STGM; + } + else{ + instr_s = "ldgm"; + instr_id = AD_INSTR_LDGM; + } + + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), "%s %s, [%s]", instr_s, Rt_s, Rn_s); + } + else if(opc == 1 && op2 == 0){ + instr_id = AD_INSTR_LDG; + + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), "ldg %s, [%s", Rt_s, Rn_s); + + if(imm9 != 0){ + signed simm = sign_extend(imm9, 9) << 4; + + ADD_IMM_OPERAND(out, AD_IMM_INT, *(S32 *)&simm); + + concat(&DECODE_STR(out), ", #"S_X"", S_A(simm)); + } + + concat(&DECODE_STR(out), "]"); + } + else if(op2 > 0){ + enum { + post = 1, signed_ = 2, pre + }; + + const char *instr_s = NULL; + + if(opc == 0){ + instr_s = "stg"; + instr_id = AD_INSTR_STG; + } + else if(opc == 1){ + instr_s = "stzg"; + instr_id = AD_INSTR_STZG; + } + else if(opc == 2){ + instr_s = "st2g"; + instr_id = AD_INSTR_ST2G; + } + else if(opc == 3){ + instr_s = "stz2g"; + instr_id = AD_INSTR_STZ2G; + } + + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), "%s %s, [%s", instr_s, Rt_s, Rn_s); + + if(imm9 == 0) + concat(&DECODE_STR(out), "]"); + else{ + signed simm = sign_extend(imm9, 9) << 4; + + ADD_IMM_OPERAND(out, AD_IMM_INT, *(S32 *)&simm); + + if(op2 == post) + concat(&DECODE_STR(out), "], #"S_X"", S_A(simm)); + else{ + concat(&DECODE_STR(out), ", #"S_X"]", S_A(simm)); + + if(op2 == pre) + concat(&DECODE_STR(out), "!"); + } + } + } + else{ + return 1; + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLoadAndStoreExclusiveInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 30, 31); + U32 o2 = bits(i->opcode, 23, 23); + U32 L = bits(i->opcode, 22, 22); + U32 o1 = bits(i->opcode, 21, 21); + U32 Rs = bits(i->opcode, 16, 20); + U32 o0 = bits(i->opcode, 15, 15); + U32 Rt2 = bits(i->opcode, 10, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + ADD_FIELD(out, size); + ADD_FIELD(out, o2); + ADD_FIELD(out, L); + ADD_FIELD(out, o1); + ADD_FIELD(out, Rs); + ADD_FIELD(out, o0); + ADD_FIELD(out, Rt2); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + U32 encoding = (o2 << 3) | (L << 2) | (o1 << 1) | o0; + S32 instr_id = AD_NONE; + + if((size == 0 || size == 1) && (encoding == 2 || encoding == 3 || + encoding == 6 || encoding == 7)){ + U32 sz = size & 1; + const char **registers = AD_RTBL_GEN_32; + + if(sz == 1) + registers = AD_RTBL_GEN_64; + + S32 rsz = (registers == AD_RTBL_GEN_64 ? _64_BIT : _32_BIT); + + const char *Rs_s = GET_GEN_REG(registers, Rs, PREFER_ZR); + const char *Rs1_s = GET_GEN_REG(registers, Rs + 1, PREFER_ZR); + const char *Rt_s = GET_GEN_REG(registers, Rt, PREFER_ZR); + const char *Rt1_s = GET_GEN_REG(registers, Rt + 1, PREFER_ZR); + + /* always 64 bit */ + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + ADD_REG_OPERAND(out, Rs, rsz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rs + 1, rsz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rt, rsz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + ADD_REG_OPERAND(out, Rt + 1, rsz, PREFER_ZR, _SYSREG(AD_NONE), _RTBL(registers)); + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + const char *instr_s = NULL; + + if(encoding == 2){ + instr_s = "casp"; + instr_id = AD_INSTR_CASP; + } + else if(encoding == 3){ + instr_s = "caspl"; + instr_id = AD_INSTR_CASPL; + } + else if(encoding == 6){ + instr_s = "caspa"; + instr_id = AD_INSTR_CASPA; + } + else{ + instr_s = "caspal"; + instr_id = AD_INSTR_CASPAL; + } + + concat(&DECODE_STR(out), "%s %s, %s, %s, %s, [%s]", instr_s, + Rs_s, Rs1_s, Rt_s, Rt1_s, Rn_s); + } + else if((size == 0 || size == 1 || size == 2 || size == 3) && + (encoding == 10 || encoding == 11 || encoding == 14 || encoding == 15)){ + const char **Rs_Rt_Rtbl = AD_RTBL_GEN_32; + U32 Rs_Rt_Sz = _32_BIT; + + if(size == 3){ + Rs_Rt_Rtbl = AD_RTBL_GEN_64; + Rs_Rt_Sz = _64_BIT; + } + + const char *Rs_s = GET_GEN_REG(Rs_Rt_Rtbl, Rs, PREFER_ZR); + const char *Rt_s = GET_GEN_REG(Rs_Rt_Rtbl, Rt, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + ADD_REG_OPERAND(out, Rs, Rs_Rt_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rs_Rt_Rtbl); + ADD_REG_OPERAND(out, Rt, Rs_Rt_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rs_Rt_Rtbl); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + const char *instr_s = NULL; + + /* we'll figure out the suffixes and adjust insn ID later */ + if(encoding == 10){ + instr_s = "cas"; + instr_id = AD_INSTR_CASB; + } + else if(encoding == 11){ + instr_s = "casl"; + instr_id = AD_INSTR_CASLB; + } + else if(encoding == 14){ + instr_s = "casa"; + instr_id = AD_INSTR_CASAB; + } + else{ + instr_s = "casal"; + instr_id = AD_INSTR_CASALB; + } + + const char *suffix = NULL; + + if(size == 0) + suffix = "b"; + else if(size == 1){ + instr_id += 4; + suffix = "h"; + } + else{ + if(encoding == 10) + instr_id += 10; + else if(encoding == 11) + instr_id += 12; + else + instr_id += 13; + + suffix = ""; + } + + concat(&DECODE_STR(out), "%s%s %s, %s, [%s]", instr_s, suffix, + Rs_s, Rt_s, Rn_s); + } + else if(size == 0 || size == 1){ + /* We'll figure out if this deals with bytes or halfwords later. + * For now, set the instruction id to the instruction which deals with + * bytes, and if we find out this instruction actually deals + * with halfwords, we increment the instruction ID. Additionally, + * we'll add the last character to the instruction string later on. + */ + struct itab tab[] = { + { "stxr", AD_INSTR_STXRB }, + { "stlxr", AD_INSTR_STLXRB }, + { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "ldxr", AD_INSTR_LDXRB }, + { "ldaxr", AD_INSTR_LDAXRB }, + { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "stllr", AD_INSTR_STLLRB }, + { "stlr", AD_INSTR_STLRB }, + { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "ldlar", AD_INSTR_LDLARB }, + { "ldar", AD_INSTR_LDARB }, + }; + + const char *instr_s = tab[encoding].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[encoding].instr_id; + + /* insn deals with bytes */ + if(size == 0) + concat(&DECODE_STR(out), "%sb ", instr_s); + else{ + concat(&DECODE_STR(out), "%sh ", instr_s); + + instr_id++; + } + + if(instr_id == AD_INSTR_STXRB || instr_id == AD_INSTR_STLXRB || + instr_id == AD_INSTR_STXRH || instr_id == AD_INSTR_STLXRH){ + const char *Rs_s = GET_GEN_REG(AD_RTBL_GEN_32, Rs, PREFER_ZR); + + ADD_REG_OPERAND(out, Rs, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_32)); + + concat(&DECODE_STR(out), "%s, ", Rs_s); + } + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_32, Rt, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + ADD_REG_OPERAND(out, Rt, _SZ(_32_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_32)); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), "%s, [%s]", Rt_s, Rn_s); + } + else if(size == 2 || size == 3){ + struct itab tab[] = { + { "stxr", AD_INSTR_STXR }, + { "stlxr", AD_INSTR_STLXR }, + { "stxp", AD_INSTR_STXP }, + { "stlxp", AD_INSTR_STLXP }, + { "ldxr", AD_INSTR_LDXR }, + { "ldaxr", AD_INSTR_LDAXR }, + { "ldxp", AD_INSTR_LDXP }, + { "ldaxp", AD_INSTR_LDAXP }, + { "stllr", AD_INSTR_STLLR }, + { "stlr", AD_INSTR_STLR }, + { NULL, AD_NONE }, + { NULL, AD_NONE }, + { "ldlar", AD_INSTR_LDLAR }, + { "ldar", AD_INSTR_LDAR }, + }; + + const char *instr_s = tab[encoding].instr_s; + + if(!instr_s) + return 1; + + instr_id = tab[encoding].instr_id; + + const char *Rs_s = GET_GEN_REG(AD_RTBL_GEN_32, Rs, PREFER_ZR); + + const char **Rt_Rtbl = AD_RTBL_GEN_32; + U32 Rt_Sz = _32_BIT; + + U32 Rt1 = Rt; + const char **Rt1_Rtbl = AD_RTBL_GEN_32; + U32 Rt1_Sz = _32_BIT; + + const char **Rt2_Rtbl = AD_RTBL_GEN_32; + U32 Rt2_Sz = _32_BIT; + + if(size == 3){ + Rt_Rtbl = AD_RTBL_GEN_64; + Rt_Sz = _64_BIT; + + Rt1_Rtbl = AD_RTBL_GEN_64; + Rt1_Sz = _64_BIT; + + Rt2_Rtbl = AD_RTBL_GEN_64; + Rt2_Sz = _64_BIT; + } + + const char *Rt_s = GET_GEN_REG(Rt_Rtbl, Rt, PREFER_ZR); + const char *Rt1_s = Rt_s; + const char *Rt2_s = GET_GEN_REG(Rt2_Rtbl, Rt2, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + concat(&DECODE_STR(out), "%s ", instr_s); + + if(instr_id == AD_INSTR_STXR || instr_id == AD_INSTR_STLXR){ + ADD_REG_OPERAND(out, Rs, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_32)); + ADD_REG_OPERAND(out, Rt, Rt_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rt_Rtbl); + + concat(&DECODE_STR(out), "%s, %s", Rs_s, Rt_s); + } + else if(instr_id == AD_INSTR_STXP || instr_id == AD_INSTR_STLXP){ + ADD_REG_OPERAND(out, Rs, _SZ(_32_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_32)); + ADD_REG_OPERAND(out, Rt1, Rt1_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rt1_Rtbl); + ADD_REG_OPERAND(out, Rt2, Rt2_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rt2_Rtbl); + + concat(&DECODE_STR(out), "%s, %s, %s", Rs_s, Rt1_s, Rt2_s); + } + else if(instr_id == AD_INSTR_LDXP || instr_id == AD_INSTR_LDAXP){ + ADD_REG_OPERAND(out, Rt1, Rt1_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rt1_Rtbl); + ADD_REG_OPERAND(out, Rt2, Rt2_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rt2_Rtbl); + + concat(&DECODE_STR(out), "%s, %s", Rt1_s, Rt2_s); + } + else{ + ADD_REG_OPERAND(out, Rt, Rt_Sz, PREFER_ZR, _SYSREG(AD_NONE), Rt_Rtbl); + + concat(&DECODE_STR(out), "%s", Rt_s); + } + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), ", [%s]", Rn_s); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLDAPR_STLRInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 30, 31); + U32 opc = bits(i->opcode, 22, 23); + U32 imm9 = bits(i->opcode, 12, 20); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + if(size == 2 && opc == 3) + return 1; + + if(size == 3 && (opc == 2 || opc == 3)) + return 1; + + ADD_FIELD(out, size); + ADD_FIELD(out, opc); + ADD_FIELD(out, imm9); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + const char *instr_s = NULL; + S32 instr_id = AD_NONE; + + imm9 = sign_extend(imm9, 9); + + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + if(size == 0){ + if(opc == 0){ + instr_s = "stlurb"; + instr_id = AD_INSTR_STLURB; + } + else if(opc == 1){ + instr_s = "ldapurb"; + instr_id = AD_INSTR_LDAPURB; + } + else{ + instr_s = "ldapursb"; + instr_id = AD_INSTR_LDAPURSB; + } + + const char *Rt_s = opc == 2 ? + GET_GEN_REG(AD_RTBL_GEN_64, Rt, PREFER_ZR) : + GET_GEN_REG(AD_RTBL_GEN_32, Rt, PREFER_ZR); + + ADD_REG_OPERAND(out, Rt, _SZ(opc == 2 ? _64_BIT : _32_BIT), + PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(opc == 2 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32)); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rt_s); + } + else if(size == 1){ + if(opc == 0){ + instr_s = "stlurh"; + instr_id = AD_INSTR_STLURH; + } + else if(opc == 1){ + instr_s = "ldapurh"; + instr_id = AD_INSTR_LDAPURH; + } + else{ + instr_s = "ldapursh"; + instr_id = AD_INSTR_LDAPURSH; + } + + const char *Rt_s = opc == 2 ? + GET_GEN_REG(AD_RTBL_GEN_64, Rt, PREFER_ZR) : + GET_GEN_REG(AD_RTBL_GEN_32, Rt, PREFER_ZR); + + ADD_REG_OPERAND(out, Rt, _SZ(opc == 2 ? _64_BIT : _32_BIT), + PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(opc == 2 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32)); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rt_s); + } + else if(size == 2){ + struct itab tab[] = { + { "stlur", AD_INSTR_STLUR }, + { "ldapur", AD_INSTR_LDAPUR }, + { "ldapursw", AD_INSTR_LDAPURSW }, + }; + + instr_s = tab[opc].instr_s; + instr_id = tab[opc].instr_id; + + const char *Rt_s = opc > 1 ? + GET_GEN_REG(AD_RTBL_GEN_64, Rt, PREFER_ZR) : + GET_GEN_REG(AD_RTBL_GEN_32, Rt, PREFER_ZR); + + ADD_REG_OPERAND(out, Rt, _SZ(opc > 1 ? _64_BIT : _32_BIT), + PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(opc > 1 ? AD_RTBL_GEN_64 : AD_RTBL_GEN_32)); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rt_s); + } + else{ + struct itab tab[] = { + { "stlur", AD_INSTR_STLUR }, + { "ldapur", AD_INSTR_LDAPUR }, + }; + + instr_s = tab[opc].instr_s; + instr_id = tab[opc].instr_id; + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, PREFER_ZR); + + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), "%s %s", instr_s, Rt_s); + } + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + _RTBL(AD_RTBL_GEN_64)); + + concat(&DECODE_STR(out), ", [%s", Rn_s); + + if(imm9 == 0) + concat(&DECODE_STR(out), "]"); + else{ + ADD_IMM_OPERAND(out, AD_IMM_INT, *(S32 *)&imm9); + + concat(&DECODE_STR(out), ", #"S_X"]", S_A(imm9)); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLoadAndStoreLiteralInstr(struct instruction *i, + struct ad_insn *out){ + U32 opc = bits(i->opcode, 30, 31); + U32 V = bits(i->opcode, 26, 26); + U32 imm19 = bits(i->opcode, 5, 23); + U32 Rt = bits(i->opcode, 0, 4); + + if(opc == 3 && V == 1) + return 1; + + ADD_FIELD(out, opc); + ADD_FIELD(out, V); + ADD_FIELD(out, imm19); + ADD_FIELD(out, Rt); + + const char *instr_s = "ldr"; + S32 instr_id = AD_INSTR_LDR; + + imm19 = sign_extend((imm19 << 2), 21); + + S64 imm = (signed)imm19 + i->PC; + + if(opc == 2 && V == 0){ + instr_s = "ldrsw"; + instr_id = AD_INSTR_LDRSW; + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + ADD_REG_OPERAND(out, Rt, _64_BIT, NO_PREFER_ZR, _SYSREG(AD_NONE), AD_RTBL_GEN_64); + + concat(&DECODE_STR(out), "%s %s, #"S_LX"", instr_s, Rt_s, S_LA(imm)); + } + else if(opc == 3 && V == 0){ + instr_s = "prfm"; + instr_id = AD_INSTR_PRFM; + + U32 type = bits(Rt, 3, 4); + U32 target = bits(Rt, 1, 2); + U32 policy = Rt & 1; + + const char *types[] = { "PLD", "PLI", "PST" }; + const char *targets[] = { "L1", "L2", "L3" }; + const char *policies[] = { "KEEP", "STRM" }; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&Rt); + + if(OOB(type, types) || OOB(target, targets) || OOB(policy, policies)) + concat(&DECODE_STR(out), "%s #%#x, #"S_LX"", instr_s, Rt, S_LA(imm)); + else{ + concat(&DECODE_STR(out), "%s %s%s%s, #"S_LX"", instr_s, types[type], + targets[target], policies[policy], S_LA(imm)); + } + } + else{ + const char *Rt_s = NULL; + + if(V == 0){ + const char **registers = AD_RTBL_GEN_32; + U32 sz = _32_BIT; + + if(opc > 0){ + registers = AD_RTBL_GEN_64; + sz = _64_BIT; + } + + Rt_s = GET_GEN_REG(registers, Rt, NO_PREFER_ZR); + ADD_REG_OPERAND(out, Rt, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), registers); + } + else{ + const char **registers_a[] = { + AD_RTBL_FP_32, AD_RTBL_FP_64, AD_RTBL_FP_128 + }; + U32 szs[] = { _32_BIT, _64_BIT, _128_BIT }; + + const char **registers = registers_a[opc]; + U32 sz = szs[opc]; + + Rt_s = GET_FP_REG(registers, Rt); + ADD_REG_OPERAND(out, Rt, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), registers); + } + + concat(&DECODE_STR(out), "%s %s, #"S_LX"", instr_s, Rt_s, S_LA(imm)); + } + + ADD_IMM_OPERAND(out, AD_IMM_LONG, *(S64 *)&imm); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLoadAndStoreRegisterPairInstr(struct instruction *i, + struct ad_insn *out, S32 kind){ + U32 opc = bits(i->opcode, 30, 31); + U32 V = bits(i->opcode, 26, 26); + U32 L = bits(i->opcode, 22, 22); + U32 imm7 = bits(i->opcode, 15, 21); + U32 Rt2 = bits(i->opcode, 10, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + if(opc == 3) + return 1; + + ADD_FIELD(out, opc); + ADD_FIELD(out, V); + ADD_FIELD(out, L); + ADD_FIELD(out, imm7); + ADD_FIELD(out, Rt2); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + const char *Rt2_s = NULL, *Rn_s = NULL, *Rt_s = NULL; + + const char **registers = NULL; + U32 sz = 0; + + if(opc == 0){ + registers = V == 0 ? AD_RTBL_GEN_32 : AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(opc == 1){ + registers = V == 0 ? AD_RTBL_GEN_64 : AD_RTBL_FP_64; + sz = _64_BIT; + } + else{ + registers = V == 0 ? AD_RTBL_GEN_64 : AD_RTBL_FP_128; + sz = V == 0 ? _64_BIT : _128_BIT; + } + + U32 scale; + + if(V == 0){ + Rt2_s = GET_FP_REG(registers, Rt2); + Rt_s = GET_FP_REG(registers, Rt); + + scale = 2 + (opc >> 1); + } + else{ + Rt2_s = GET_GEN_REG(registers, Rt2, NO_PREFER_ZR); + Rt_s = GET_GEN_REG(registers, Rt, NO_PREFER_ZR); + + scale = 2 + opc; + } + + Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + ADD_REG_OPERAND(out, Rt, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), registers); + ADD_REG_OPERAND(out, Rt2, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), registers); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + AD_RTBL_GEN_64); + + U32 opco = (opc << 2) | (V << 1) | L; + + /* start at AD_INSTR_(STP|LDP) and adjust as needed */ + + if(L == 0){ + instr_id = AD_INSTR_STP; + + concat(&DECODE_STR(out), "st"); + } + else{ + instr_id = AD_INSTR_LDP; + + concat(&DECODE_STR(out), "ld"); + } + + if(kind == NO_ALLOCATE){ + instr_id--; + concat(&DECODE_STR(out), "n"); + } + else{ + if(opco == 4){ + instr_id -= 15; + + concat(&DECODE_STR(out), "g"); + + scale = 4; + } + } + + concat(&DECODE_STR(out), "p"); + + if(kind != NO_ALLOCATE && opco == 5){ + instr_id++; + + concat(&DECODE_STR(out), "sw"); + } + + concat(&DECODE_STR(out), " %s, %s, [%s", Rt_s, Rt2_s, Rn_s); + + imm7 = sign_extend(imm7, 7) << scale; + + if(imm7 == 0) + concat(&DECODE_STR(out), "]"); + else{ + if(kind == POST_INDEXED) + concat(&DECODE_STR(out), "], #"S_X"", S_A(imm7)); + else if(kind == OFFSET || kind == NO_ALLOCATE) + concat(&DECODE_STR(out), ", #"S_X"]", S_A(imm7)); + else + concat(&DECODE_STR(out), ", #"S_X"]!", S_A(imm7)); + + ADD_IMM_OPERAND(out, AD_IMM_INT, *(S32 *)&imm7); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLoadAndStoreRegisterInstr(struct instruction *i, + struct ad_insn *out, S32 kind){ + U32 size = bits(i->opcode, 30, 31); + U32 V = bits(i->opcode, 26, 26); + U32 opc = bits(i->opcode, 22, 23); + U32 imm9 = bits(i->opcode, 12, 20); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + ADD_FIELD(out, size); + ADD_FIELD(out, V); + ADD_FIELD(out, opc); + ADD_FIELD(out, imm9); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + const char **registers = AD_RTBL_GEN_32; + U32 sz = _32_BIT; + + const char *Rt_s = GET_GEN_REG(registers, Rt, PREFER_ZR); + + if(V == 0 && (opc == 2 || size == 3)){ + registers = AD_RTBL_GEN_64; + sz = _64_BIT; + + Rt_s = GET_GEN_REG(registers, Rt, PREFER_ZR); + } + else if(V == 1){ + if(size == 0 && (opc == 0 || opc == 1)){ + registers = AD_RTBL_FP_8; + sz = _8_BIT; + } + else if(size == 0 && (opc == 2 || opc == 3)){ + registers = AD_RTBL_FP_128; + sz = _128_BIT; + } + else if(size == 1 && (opc == 0 || opc == 1)){ + registers = AD_RTBL_FP_16; + sz = _16_BIT; + } + else if(size == 2 && (opc == 0 || opc == 1)){ + registers = AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(size == 3 && (opc == 0 || opc == 1)){ + registers = AD_RTBL_FP_64; + sz = _64_BIT; + } + + Rt_s = GET_FP_REG(registers, Rt); + } + + ADD_REG_OPERAND(out, Rt, sz, PREFER_ZR, _SYSREG(AD_NONE), registers); + + U32 instr_idx = (size << 3) | (V << 2) | opc; + struct itab *instr_tab = NULL; + + if(kind == UNSIGNED_IMMEDIATE || kind == IMMEDIATE_POST_INDEXED || + kind == IMMEDIATE_PRE_INDEXED){ + if(OOB(instr_idx, pre_post_unsigned_register_idx_instr_tbl)) + return 1; + + instr_tab = pre_post_unsigned_register_idx_instr_tbl; + } + else if(kind == UNPRIVILEGED){ + if(OOB(instr_idx, unprivileged_instr_tbl)) + return 1; + + instr_tab = unprivileged_instr_tbl; + } + else if(kind == UNSCALED_IMMEDIATE){ + if(OOB(instr_idx, unscaled_instr_tbl)) + return 1; + + instr_tab = unscaled_instr_tbl; + } + + if(!instr_tab) + return 1; + + const char *instr_s = instr_tab[instr_idx].instr_s; + + if(!instr_s) + return 1; + + instr_id = instr_tab[instr_idx].instr_id; + + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), + AD_RTBL_GEN_64); + + concat(&DECODE_STR(out), "%s ", instr_s); + + imm9 = sign_extend(imm9, 9); + + if(instr_id == AD_INSTR_PRFUM){ + U32 type = bits(Rt, 3, 4); + U32 target = bits(Rt, 1, 2); + U32 policy = Rt & 1; + + const char *types[] = { "PLD", "PLI", "PST" }; + const char *targets[] = { "L1", "L2", "L3" }; + const char *policies[] = { "KEEP", "STRM" }; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm9); + + if(OOB(type, types) || OOB(target, targets) || OOB(policy, policies)) + concat(&DECODE_STR(out), "#%#x, ", Rt); + else{ + concat(&DECODE_STR(out), "%s%s%s, ", types[type], targets[target], + policies[policy]); + } + } + else{ + concat(&DECODE_STR(out), "%s, [%s", Rt_s, Rn_s); + + if(kind == UNSCALED_IMMEDIATE || kind == UNPRIVILEGED){ + if(imm9 == 0) + concat(&DECODE_STR(out), "]"); + else + concat(&DECODE_STR(out), ", #"S_X"]", S_A(imm9)); + } + else if(kind == UNSIGNED_IMMEDIATE){ + U32 imm12 = bits(i->opcode, 10, 21); + + S32 fp = V == 1; + S32 shift = 0; + + if(fp) + shift = ((opc >> 1) << 2) | size; + else if(instr_id == AD_INSTR_LDRH || instr_id == AD_INSTR_STRH || + instr_id == AD_INSTR_LDRSH){ + shift = 1; + } + else if(instr_id == AD_INSTR_LDRSW){ + shift = 2; + } + else if(instr_id == AD_INSTR_STR || instr_id == AD_INSTR_LDR){ + shift = size; + } + + U64 pimm = imm12 << shift; + + if(pimm != 0){ + ADD_IMM_OPERAND(out, AD_IMM_ULONG, *(U64 *)&pimm); + + concat(&DECODE_STR(out), ", #"S_LX"", S_LA(pimm)); + } + + concat(&DECODE_STR(out), "]"); + } + else if(kind == IMMEDIATE_POST_INDEXED){ + concat(&DECODE_STR(out), "], #"S_X"", S_A(imm9)); + } + else if(kind == IMMEDIATE_PRE_INDEXED){ + concat(&DECODE_STR(out), ", #"S_X"]!", S_A(imm9)); + } + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +/* returns 1 if the alias is meant to be used */ +static S32 get_atomic_memory_op(U32 size, U32 V, U32 A, + U32 R, U32 o3, U32 opc, U32 Rt, struct itab *instr, + struct itab *alias){ + U32 encoding = size << 7; + encoding |= V << 6; + encoding |= A << 5; + encoding |= R << 4; + encoding |= o3 << 3; + encoding |= opc; + + S32 use_alias = (A == 0 && Rt == 0x1f); + + switch(encoding){ + case 0x184: + { + instr->instr_s = "ldsmax"; + instr->instr_id = AD_INSTR_LDSMAX; + alias->instr_s = "stsmax"; + alias->instr_id = AD_INSTR_STSMAX; + break; + } + case 0x110: + { + instr->instr_s = "ldaddl"; + instr->instr_id = AD_INSTR_LDADDL; + alias->instr_s = "staddl"; + alias->instr_id = AD_INSTR_STADDL; + break; + } + case 0x1b4: + { + instr->instr_s = "ldsmaxal"; + instr->instr_id = AD_INSTR_LDSMAXAL; + break; + } + case 0x120: + { + instr->instr_s = "ldadda"; + instr->instr_id = AD_INSTR_LDADDA; + break; + } + case 0xac: + { + instr->instr_s = "ldaprh"; + instr->instr_id = AD_INSTR_LDAPRH; + break; + } + case 0x38: + { + instr->instr_s = "swpalb"; + instr->instr_id = AD_INSTR_SWPALB; + break; + } + case 0x8: + { + instr->instr_s = "swpb"; + instr->instr_id = AD_INSTR_SWPB; + break; + } + case 0xa1: + { + instr->instr_s = "ldclrah"; + instr->instr_id = AD_INSTR_LDCLRAH; + break; + } + case 0x35: + { + instr->instr_s = "ldsminalb"; + instr->instr_id = AD_INSTR_LDSMINALB; + break; + } + case 0x91: + { + instr->instr_s = "ldclrlh"; + instr->instr_id = AD_INSTR_LDCLRLH; + alias->instr_s = "stclrlh"; + alias->instr_id = AD_INSTR_STCLRLH; + break; + } + case 0x5: + { + instr->instr_s = "ldsminb"; + instr->instr_id = AD_INSTR_LDSMINB; + alias->instr_s = "stsminb"; + alias->instr_id = AD_INSTR_STSMINB; + break; + } + case 0x97: + { + instr->instr_s = "lduminlh"; + instr->instr_id = AD_INSTR_LDUMINLH; + alias->instr_s = "stuminlh"; + alias->instr_id = AD_INSTR_STUMINLH; + break; + } + case 0x3: + { + instr->instr_s = "ldsetb"; + instr->instr_id = AD_INSTR_LDSETB; + alias->instr_s = "stsetb"; + alias->instr_id = AD_INSTR_STSETB; + break; + } + case 0xa7: + { + instr->instr_s = "lduminah"; + instr->instr_id = AD_INSTR_LDUMINAH; + break; + } + case 0x33: + { + instr->instr_s = "ldsetalb"; + instr->instr_id = AD_INSTR_LDSETALB; + break; + } + case 0x1b2: + { + instr->instr_s = "ldeoral"; + instr->instr_id = AD_INSTR_LDEORAL; + break; + } + case 0x126: + { + instr->instr_s = "ldumaxa"; + instr->instr_id = AD_INSTR_LDUMAXA; + break; + } + case 0x182: + { + instr->instr_s = "ldeor"; + instr->instr_id = AD_INSTR_LDEOR; + alias->instr_s = "steor"; + alias->instr_id = AD_INSTR_STEOR; + break; + } + case 0x116: + { + instr->instr_s = "ldumaxl"; + instr->instr_id = AD_INSTR_LDUMAXL; + alias->instr_s = "stumaxl"; + alias->instr_id = AD_INSTR_STUMAXL; + break; + } + case 0x105: + { + instr->instr_s = "ldsmin"; + instr->instr_id = AD_INSTR_LDSMIN; + alias->instr_s = "stsmin"; + alias->instr_id = AD_INSTR_STSMIN; + break; + } + case 0x191: + { + instr->instr_s = "ldclrl"; + instr->instr_id = AD_INSTR_LDCLRL; + alias->instr_s = "stclrl"; + alias->instr_id = AD_INSTR_STCLRL; + break; + } + case 0x135: + { + instr->instr_s = "ldsminal"; + instr->instr_id = AD_INSTR_LDSMINAL; + break; + } + case 0x1a1: + { + instr->instr_s = "ldclra"; + instr->instr_id = AD_INSTR_LDCLRA; + break; + } + case 0x108: + { + instr->instr_s = "swp"; + instr->instr_id = AD_INSTR_SWP; + break; + } + case 0x138: + { + instr->instr_s = "swpal"; + instr->instr_id = AD_INSTR_SWPAL; + break; + } + case 0x1ac: + { + instr->instr_s = "ldaddal"; + instr->instr_id = AD_INSTR_LDADDAL; + break; + } + case 0x20: + { + instr->instr_s = "ldaddab"; + instr->instr_id = AD_INSTR_LDADDAB; + break; + } + case 0xb4: + { + instr->instr_s = "ldsmaxalh"; + instr->instr_id = AD_INSTR_LDSMAXALH; + break; + } + case 0x10: + { + instr->instr_s = "ldaddlb"; + instr->instr_id = AD_INSTR_LDADDLB; + alias->instr_s = "staddlb"; + alias->instr_id = AD_INSTR_STADDLB; + break; + } + case 0x84: + { + instr->instr_s = "ldsmaxh"; + instr->instr_id = AD_INSTR_LDSMAXH; + alias->instr_s = "stsmaxh"; + alias->instr_id = AD_INSTR_STSMAXH; + break; + } + case 0x16: + { + instr->instr_s = "ldumaxlb"; + instr->instr_id = AD_INSTR_LDUMAXLB; + alias->instr_s = "stumaxlb"; + alias->instr_id = AD_INSTR_STUMAXLB; + break; + } + case 0x82: + { + instr->instr_s = "ldeorh"; + instr->instr_id = AD_INSTR_LDEORH; + alias->instr_s = "steorh"; + alias->instr_id = AD_INSTR_STEORH; + break; + } + case 0x26: + { + instr->instr_s = "ldumaxab"; + instr->instr_id = AD_INSTR_LDUMAXAB; + break; + } + case 0xb2: + { + instr->instr_s = "ldeoralh"; + instr->instr_id = AD_INSTR_LDEORALH; + break; + } + case 0x133: + { + instr->instr_s = "ldsetal"; + instr->instr_id = AD_INSTR_LDSETAL; + break; + } + case 0x1a7: + { + instr->instr_s = "ldumina"; + instr->instr_id = AD_INSTR_LDUMINA; + break; + } + case 0x103: + { + instr->instr_s = "ldset"; + instr->instr_id = AD_INSTR_LDSET; + alias->instr_s = "stset"; + alias->instr_id = AD_INSTR_STSET; + break; + } + case 0x197: + { + instr->instr_s = "lduminl"; + instr->instr_id = AD_INSTR_LDUMINL; + alias->instr_s = "stuminl"; + alias->instr_id = AD_INSTR_STUMINL; + break; + } + case 0x180: + { + instr->instr_s = "ldadd"; + instr->instr_id = AD_INSTR_LDADD; + alias->instr_s = "stadd"; + alias->instr_id = AD_INSTR_STADD; + break; + } + case 0x114: + { + instr->instr_s = "ldsmaxl"; + instr->instr_id = AD_INSTR_LDSMAXL; + alias->instr_s = "stsmaxl"; + alias->instr_id = AD_INSTR_STSMAXL; + break; + } + case 0x124: + { + instr->instr_s = "ldsmaxa"; + instr->instr_id = AD_INSTR_LDSMAXA; + break; + } + case 0xa8: + { + instr->instr_s = "swpah"; + instr->instr_id = AD_INSTR_SWPAH; + break; + } + case 0x98: + { + instr->instr_s = "swplh"; + instr->instr_id = AD_INSTR_SWPLH; + break; + } + case 0xa5: + { + instr->instr_s = "ldsminah"; + instr->instr_id = AD_INSTR_LDSMINAH; + break; + } + case 0x31: + { + instr->instr_s = "ldclralb"; + instr->instr_id = AD_INSTR_LDCLRALB; + break; + } + case 0x95: + { + instr->instr_s = "ldsminlh"; + instr->instr_id = AD_INSTR_LDSMINLH; + alias->instr_s = "stsminlh"; + alias->instr_id = AD_INSTR_STSMINLH; + break; + } + case 0x1: + { + instr->instr_s = "ldclrb"; + instr->instr_id = AD_INSTR_LDCLRB; + alias->instr_s = "stclrb"; + alias->instr_id = AD_INSTR_STCLRB; + break; + } + case 0x93: + { + instr->instr_s = "ldsetlh"; + instr->instr_id = AD_INSTR_LDSETLH; + alias->instr_s = "stsetlh"; + alias->instr_id = AD_INSTR_STSETLH; + break; + } + case 0x7: + { + instr->instr_s = "lduminb"; + instr->instr_id = AD_INSTR_LDUMINB; + alias->instr_s = "stuminb"; + alias->instr_id = AD_INSTR_STUMINB; + break; + } + case 0xa3: + { + instr->instr_s = "ldsetah"; + instr->instr_id = AD_INSTR_LDSETAH; + break; + } + case 0x37: + { + instr->instr_s = "lduminalb"; + instr->instr_id = AD_INSTR_LDUMINALB; + break; + } + case 0x1b6: + { + instr->instr_s = "ldumaxal"; + instr->instr_id = AD_INSTR_LDUMAXAL; + break; + } + case 0x122: + { + instr->instr_s = "ldeora"; + instr->instr_id = AD_INSTR_LDEORA; + break; + } + case 0x186: + { + instr->instr_s = "ldumax"; + instr->instr_id = AD_INSTR_LDUMAX; + alias->instr_s = "stumax"; + alias->instr_id = AD_INSTR_STUMAX; + break; + } + case 0x112: + { + instr->instr_s = "ldeorl"; + instr->instr_id = AD_INSTR_LDEORL; + alias->instr_s = "steorl"; + alias->instr_id = AD_INSTR_STEORL; + break; + } + case 0x101: + { + instr->instr_s = "ldclr"; + instr->instr_id = AD_INSTR_LDCLR; + alias->instr_s = "stclr"; + alias->instr_id = AD_INSTR_STCLR; + break; + } + case 0x195: + { + instr->instr_s = "ldsminl"; + instr->instr_id = AD_INSTR_LDSMINL; + alias->instr_s = "stsminl"; + alias->instr_id = AD_INSTR_STSMINL; + break; + } + case 0x131: + { + instr->instr_s = "ldclral"; + instr->instr_id = AD_INSTR_LDCLRAL; + break; + } + case 0x1a5: + { + instr->instr_s = "ldsmina"; + instr->instr_id = AD_INSTR_LDSMINA; + break; + } + case 0x198: + { + instr->instr_s = "swpl"; + instr->instr_id = AD_INSTR_SWPL; + break; + } + case 0x1a8: + { + instr->instr_s = "swpa"; + instr->instr_id = AD_INSTR_SWPA; + break; + } + case 0x24: + { + instr->instr_s = "ldsmaxab"; + instr->instr_id = AD_INSTR_LDSMAXAB; + break; + } + case 0xb0: + { + instr->instr_s = "ldaddalh"; + instr->instr_id = AD_INSTR_LDADDALH; + break; + } + case 0x14: + { + instr->instr_s = "ldsmaxlb"; + instr->instr_id = AD_INSTR_LDSMAXLB; + alias->instr_s = "stsmaxlb"; + alias->instr_id = AD_INSTR_STSMAXLB; + break; + } + case 0x80: + { + instr->instr_s = "ldaddh"; + instr->instr_id = AD_INSTR_LDADDH; + alias->instr_s = "staddh"; + alias->instr_id = AD_INSTR_STADDH; + break; + } + case 0x12: + { + instr->instr_s = "ldeorlb"; + instr->instr_id = AD_INSTR_LDEORLB; + alias->instr_s = "steorlb"; + alias->instr_id = AD_INSTR_STEORLB; + break; + } + case 0x86: + { + instr->instr_s = "ldumaxh"; + instr->instr_id = AD_INSTR_LDUMAXH; + alias->instr_s = "stumaxh"; + alias->instr_id = AD_INSTR_STUMAXH; + break; + } + case 0x22: + { + instr->instr_s = "ldeorab"; + instr->instr_id = AD_INSTR_LDEORAB; + break; + } + case 0xb6: + { + instr->instr_s = "ldumaxalh"; + instr->instr_id = AD_INSTR_LDUMAXALH; + break; + } + case 0x137: + { + instr->instr_s = "lduminal"; + instr->instr_id = AD_INSTR_LDUMINAL; + break; + } + case 0x1a3: + { + instr->instr_s = "ldseta"; + instr->instr_id = AD_INSTR_LDSETA; + break; + } + case 0x107: + { + instr->instr_s = "ldumin"; + instr->instr_id = AD_INSTR_LDUMIN; + alias->instr_s = "stumin"; + alias->instr_id = AD_INSTR_STUMIN; + break; + } + case 0x193: + { + instr->instr_s = "ldsetl"; + instr->instr_id = AD_INSTR_LDSETL; + alias->instr_s = "stsetl"; + alias->instr_id = AD_INSTR_STSETL; + break; + } + case 0x30: + { + instr->instr_s = "ldaddalb"; + instr->instr_id = AD_INSTR_LDADDALB; + break; + } + case 0xa4: + { + instr->instr_s = "ldsmaxah"; + instr->instr_id = AD_INSTR_LDSMAXAH; + break; + } + case 0x0: + { + instr->instr_s = "ldaddb"; + instr->instr_id = AD_INSTR_LDADDB; + alias->instr_s = "staddb"; + alias->instr_id = AD_INSTR_STADDB; + break; + } + case 0x94: + { + instr->instr_s = "ldsmaxlh"; + instr->instr_id = AD_INSTR_LDSMAXLH; + alias->instr_s = "stsmaxlh"; + alias->instr_id = AD_INSTR_STSMAXLH; + break; + } + case 0x115: + { + instr->instr_s = "ldsminl"; + instr->instr_id = AD_INSTR_LDSMINL; + alias->instr_s = "stsminl"; + alias->instr_id = AD_INSTR_STSMINL; + break; + } + case 0x181: + { + instr->instr_s = "ldclr"; + instr->instr_id = AD_INSTR_LDCLR; + alias->instr_s = "stclr"; + alias->instr_id = AD_INSTR_STCLR; + break; + } + case 0x125: + { + instr->instr_s = "ldsmina"; + instr->instr_id = AD_INSTR_LDSMINA; + break; + } + case 0x1b1: + { + instr->instr_s = "ldclral"; + instr->instr_id = AD_INSTR_LDCLRAL; + break; + } + case 0x118: + { + instr->instr_s = "swpl"; + instr->instr_id = AD_INSTR_SWPL; + break; + } + case 0x128: + { + instr->instr_s = "swpa"; + instr->instr_id = AD_INSTR_SWPA; + break; + } + case 0x123: + { + instr->instr_s = "ldseta"; + instr->instr_id = AD_INSTR_LDSETA; + break; + } + case 0x1b7: + { + instr->instr_s = "lduminal"; + instr->instr_id = AD_INSTR_LDUMINAL; + break; + } + case 0x113: + { + instr->instr_s = "ldsetl"; + instr->instr_id = AD_INSTR_LDSETL; + alias->instr_s = "stsetl"; + alias->instr_id = AD_INSTR_STSETL; + break; + } + case 0x187: + { + instr->instr_s = "ldumin"; + instr->instr_id = AD_INSTR_LDUMIN; + alias->instr_s = "stumin"; + alias->instr_id = AD_INSTR_STUMIN; + break; + } + case 0x6: + { + instr->instr_s = "ldumaxb"; + instr->instr_id = AD_INSTR_LDUMAXB; + alias->instr_s = "stumaxb"; + alias->instr_id = AD_INSTR_STUMAXB; + break; + } + case 0x92: + { + instr->instr_s = "ldeorlh"; + instr->instr_id = AD_INSTR_LDEORLH; + alias->instr_s = "steorlh"; + alias->instr_id = AD_INSTR_STEORLH; + break; + } + case 0x36: + { + instr->instr_s = "ldumaxalb"; + instr->instr_id = AD_INSTR_LDUMAXALB; + break; + } + case 0xa2: + { + instr->instr_s = "ldeorah"; + instr->instr_id = AD_INSTR_LDEORAH; + break; + } + case 0x28: + { + instr->instr_s = "swpab"; + instr->instr_id = AD_INSTR_SWPAB; + break; + } + case 0x18: + { + instr->instr_s = "swplb"; + instr->instr_id = AD_INSTR_SWPLB; + break; + } + case 0xb1: + { + instr->instr_s = "ldclralh"; + instr->instr_id = AD_INSTR_LDCLRALH; + break; + } + case 0x25: + { + instr->instr_s = "ldsminab"; + instr->instr_id = AD_INSTR_LDSMINAB; + break; + } + case 0x81: + { + instr->instr_s = "ldclrh"; + instr->instr_id = AD_INSTR_LDCLRH; + alias->instr_s = "stclrh"; + alias->instr_id = AD_INSTR_STCLRH; + break; + } + case 0x15: + { + instr->instr_s = "ldsminlb"; + instr->instr_id = AD_INSTR_LDSMINLB; + alias->instr_s = "stsminlb"; + alias->instr_id = AD_INSTR_STSMINLB; + break; + } + case 0x194: + { + instr->instr_s = "ldsmaxl"; + instr->instr_id = AD_INSTR_LDSMAXL; + alias->instr_s = "stsmaxl"; + alias->instr_id = AD_INSTR_STSMAXL; + break; + } + case 0x100: + { + instr->instr_s = "ldadd"; + instr->instr_id = AD_INSTR_LDADD; + alias->instr_s = "stadd"; + alias->instr_id = AD_INSTR_STADD; + break; + } + case 0x1a4: + { + instr->instr_s = "ldsmaxa"; + instr->instr_id = AD_INSTR_LDSMAXA; + break; + } + case 0x1a2: + { + instr->instr_s = "ldeora"; + instr->instr_id = AD_INSTR_LDEORA; + break; + } + case 0x136: + { + instr->instr_s = "ldumaxal"; + instr->instr_id = AD_INSTR_LDUMAXAL; + break; + } + case 0x192: + { + instr->instr_s = "ldeorl"; + instr->instr_id = AD_INSTR_LDEORL; + alias->instr_s = "steorl"; + alias->instr_id = AD_INSTR_STEORL; + break; + } + case 0x106: + { + instr->instr_s = "ldumax"; + instr->instr_id = AD_INSTR_LDUMAX; + alias->instr_s = "stumax"; + alias->instr_id = AD_INSTR_STUMAX; + break; + } + case 0x87: + { + instr->instr_s = "lduminh"; + instr->instr_id = AD_INSTR_LDUMINH; + alias->instr_s = "stuminh"; + alias->instr_id = AD_INSTR_STUMINH; + break; + } + case 0x13: + { + instr->instr_s = "ldsetlb"; + instr->instr_id = AD_INSTR_LDSETLB; + alias->instr_s = "stsetlb"; + alias->instr_id = AD_INSTR_STSETLB; + break; + } + case 0xb7: + { + instr->instr_s = "lduminalh"; + instr->instr_id = AD_INSTR_LDUMINALH; + break; + } + case 0x23: + { + instr->instr_s = "ldsetab"; + instr->instr_id = AD_INSTR_LDSETAB; + break; + } + case 0x34: + { + instr->instr_s = "ldsmaxalb"; + instr->instr_id = AD_INSTR_LDSMAXALB; + break; + } + case 0xa0: + { + instr->instr_s = "ldaddah"; + instr->instr_id = AD_INSTR_LDADDAH; + break; + } + case 0x4: + { + instr->instr_s = "ldsmaxb"; + instr->instr_id = AD_INSTR_LDSMAXB; + alias->instr_s = "stsmaxb"; + alias->instr_id = AD_INSTR_STSMAXB; + break; + } + case 0x90: + { + instr->instr_s = "ldaddlh"; + instr->instr_id = AD_INSTR_LDADDLH; + alias->instr_s = "staddlh"; + alias->instr_id = AD_INSTR_STADDLH; + break; + } + case 0x111: + { + instr->instr_s = "ldclrl"; + instr->instr_id = AD_INSTR_LDCLRL; + alias->instr_s = "stclrl"; + alias->instr_id = AD_INSTR_STCLRL; + break; + } + case 0x185: + { + instr->instr_s = "ldsmin"; + instr->instr_id = AD_INSTR_LDSMIN; + alias->instr_s = "stsmin"; + alias->instr_id = AD_INSTR_STSMIN; + break; + } + case 0x121: + { + instr->instr_s = "ldclra"; + instr->instr_id = AD_INSTR_LDCLRA; + break; + } + case 0x1b5: + { + instr->instr_s = "ldsminal"; + instr->instr_id = AD_INSTR_LDSMINAL; + break; + } + case 0x188: + { + instr->instr_s = "swp"; + instr->instr_id = AD_INSTR_SWP; + break; + } + case 0x130: + { + instr->instr_s = "ldaddal"; + instr->instr_id = AD_INSTR_LDADDAL; + break; + } + case 0x1b8: + { + instr->instr_s = "swpal"; + instr->instr_id = AD_INSTR_SWPAL; + break; + } + case 0x127: + { + instr->instr_s = "ldumina"; + instr->instr_id = AD_INSTR_LDUMINA; + break; + } + case 0x1b3: + { + instr->instr_s = "ldsetal"; + instr->instr_id = AD_INSTR_LDSETAL; + break; + } + case 0x117: + { + instr->instr_s = "lduminl"; + instr->instr_id = AD_INSTR_LDUMINL; + alias->instr_s = "stuminl"; + alias->instr_id = AD_INSTR_STUMINL; + break; + } + case 0x183: + { + instr->instr_s = "ldset"; + instr->instr_id = AD_INSTR_LDSET; + alias->instr_s = "stset"; + alias->instr_id = AD_INSTR_STSET; + break; + } + case 0x2: + { + instr->instr_s = "ldeorb"; + instr->instr_id = AD_INSTR_LDEORB; + alias->instr_s = "steorb"; + alias->instr_id = AD_INSTR_STEORB; + break; + } + case 0x96: + { + instr->instr_s = "ldumaxlh"; + instr->instr_id = AD_INSTR_LDUMAXLH; + alias->instr_s = "stumaxlh"; + alias->instr_id = AD_INSTR_STUMAXLH; + break; + } + case 0x32: + { + instr->instr_s = "ldeoralb"; + instr->instr_id = AD_INSTR_LDEORALB; + break; + } + case 0xa6: + { + instr->instr_s = "ldumaxah"; + instr->instr_id = AD_INSTR_LDUMAXAH; + break; + } + case 0xb8: + { + instr->instr_s = "swpalh"; + instr->instr_id = AD_INSTR_SWPALH; + break; + } + case 0x2c: + { + instr->instr_s = "ldaprb"; + instr->instr_id = AD_INSTR_LDAPRB; + break; + } + case 0x88: + { + instr->instr_s = "swph"; + instr->instr_id = AD_INSTR_SWPH; + break; + } + case 0xb5: + { + instr->instr_s = "ldsminalh"; + instr->instr_id = AD_INSTR_LDSMINALH; + break; + } + case 0x21: + { + instr->instr_s = "ldclrab"; + instr->instr_id = AD_INSTR_LDCLRAB; + break; + } + case 0x85: + { + instr->instr_s = "ldsminh"; + instr->instr_id = AD_INSTR_LDSMINH; + alias->instr_s = "stsminh"; + alias->instr_id = AD_INSTR_STSMINH; + break; + } + case 0x11: + { + instr->instr_s = "ldclrlb"; + instr->instr_id = AD_INSTR_LDCLRLB; + alias->instr_s = "stclrlb"; + alias->instr_id = AD_INSTR_STCLRLB; + break; + } + case 0x190: + { + instr->instr_s = "ldaddl"; + instr->instr_id = AD_INSTR_LDADDL; + alias->instr_s = "staddl"; + alias->instr_id = AD_INSTR_STADDL; + break; + } + case 0x104: + { + instr->instr_s = "ldsmax"; + instr->instr_id = AD_INSTR_LDSMAX; + alias->instr_s = "stsmax"; + alias->instr_id = AD_INSTR_STSMAX; + break; + } + case 0x1a0: + { + instr->instr_s = "ldadda"; + instr->instr_id = AD_INSTR_LDADDA; + break; + } + case 0x134: + { + instr->instr_s = "ldsmaxal"; + instr->instr_id = AD_INSTR_LDSMAXAL; + break; + } + case 0x1a6: + { + instr->instr_s = "ldumaxa"; + instr->instr_id = AD_INSTR_LDUMAXA; + break; + } + case 0x132: + { + instr->instr_s = "ldeoral"; + instr->instr_id = AD_INSTR_LDEORAL; + break; + } + case 0x196: + { + instr->instr_s = "ldumaxl"; + instr->instr_id = AD_INSTR_LDUMAXL; + alias->instr_s = "stumaxl"; + alias->instr_id = AD_INSTR_STUMAXL; + break; + } + case 0x102: + { + instr->instr_s = "ldeor"; + instr->instr_id = AD_INSTR_LDEOR; + alias->instr_s = "steor"; + alias->instr_id = AD_INSTR_STEOR; + break; + } + case 0x83: + { + instr->instr_s = "ldseth"; + instr->instr_id = AD_INSTR_LDSETH; + alias->instr_s = "stseth"; + alias->instr_id = AD_INSTR_STSETH; + break; + } + case 0x17: + { + instr->instr_s = "lduminlb"; + instr->instr_id = AD_INSTR_LDUMINLB; + alias->instr_s = "stuminlb"; + alias->instr_id = AD_INSTR_STUMINLB; + break; + } + case 0xb3: + { + instr->instr_s = "ldsetalh"; + instr->instr_id = AD_INSTR_LDSETALH; + break; + } + case 0x27: + { + instr->instr_s = "lduminab"; + instr->instr_id = AD_INSTR_LDUMINAB; + break; + } + case 0x12c: + { + instr->instr_s = "ldapr"; + instr->instr_id = AD_INSTR_LDAPR; + break; + } + }; + + return use_alias; +} + +static S32 DisassembleAtomicMemoryInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 30, 31); + U32 V = bits(i->opcode, 26, 26); + U32 A = bits(i->opcode, 23, 23); + U32 R = bits(i->opcode, 22, 22); + U32 Rs = bits(i->opcode, 16, 20); + U32 o3 = bits(i->opcode, 15, 15); + U32 opc = bits(i->opcode, 12, 14); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + ADD_FIELD(out, size); + ADD_FIELD(out, V); + ADD_FIELD(out, A); + ADD_FIELD(out, R); + ADD_FIELD(out, Rs); + ADD_FIELD(out, o3); + ADD_FIELD(out, opc); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + if(V == 1) + return 1; + + const char **registers = AD_RTBL_GEN_32; + U64 sz = AD_RTBL_GEN_32_SZ; + + if(size > 2){ + registers = AD_RTBL_GEN_64; + sz = AD_RTBL_GEN_64_SZ; + } + + const char *Rs_s = GET_GEN_REG(registers, Rs, PREFER_ZR); + const char *Rt_s = GET_GEN_REG(registers, Rt, PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + struct itab instr = {0}, alias = {0}; + + S32 use_alias = get_atomic_memory_op(size, V, A, R, o3, opc, Rt, &instr, &alias); + + S32 instr_id = AD_NONE; + + if(use_alias){ + if(!alias.instr_s) + return 1; + + concat(&DECODE_STR(out), "%s ", alias.instr_s); + + instr_id = alias.instr_id; + } + else{ + if(!instr.instr_s) + return 1; + + concat(&DECODE_STR(out), "%s ", instr.instr_s); + + instr_id = instr.instr_id; + } + + if(instr_id == AD_INSTR_LDAPR || instr_id == AD_INSTR_LDAPRB || + instr_id == AD_INSTR_LDAPRH){ + ADD_REG_OPERAND(out, Rt, sz, PREFER_ZR, _SYSREG(AD_NONE), registers); + + concat(&DECODE_STR(out), "%s, ", Rt_s); + } + else{ + ADD_REG_OPERAND(out, Rs, sz, PREFER_ZR, _SYSREG(AD_NONE), registers); + + concat(&DECODE_STR(out), "%s, ", Rs_s); + + /* alias omits Rt */ + if(!use_alias){ + ADD_REG_OPERAND(out, Rt, sz, PREFER_ZR, _SYSREG(AD_NONE), registers); + + concat(&DECODE_STR(out), "%s, ", Rt_s); + } + } + + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), registers); + + concat(&DECODE_STR(out), "[%s]", Rn_s); + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +static S32 DisassembleLoadAndStoreRegisterOffsetInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 30, 31); + U32 V = bits(i->opcode, 26, 26); + U32 opc = bits(i->opcode, 22, 23); + U32 Rm = bits(i->opcode, 16, 20); + U32 option = bits(i->opcode, 13, 15); + U32 S = bits(i->opcode, 12, 12); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + ADD_FIELD(out, size); + ADD_FIELD(out, V); + ADD_FIELD(out, opc); + ADD_FIELD(out, Rm); + ADD_FIELD(out, option); + ADD_FIELD(out, S); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + const char **registers = AD_RTBL_GEN_32; + U64 sz = _32_BIT; + + S32 fp = 0; + + if(V == 0 && (opc == 2 || size == 3)){ + registers = AD_RTBL_GEN_64; + sz = _64_BIT; + } + else if(V == 1){ + fp = 1; + + if(size == 0 && opc != 2){ + registers = AD_RTBL_FP_8; + sz = _8_BIT; + } + else if(size == 0 && (opc == 2 || opc == 3)){ + registers = AD_RTBL_FP_128; + sz = _128_BIT; + } + else if(size == 1){ + registers = AD_RTBL_FP_16; + sz = _16_BIT; + } + else if(size == 2){ + registers = AD_RTBL_FP_32; + sz = _32_BIT; + } + else if(size == 3){ + registers = AD_RTBL_FP_64; + sz = _64_BIT; + } + } + + const char *Rt_s = NULL; + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + const char *Rm_s = NULL; + + if(fp) + Rt_s = GET_FP_REG(registers, Rt); + else + Rt_s = GET_GEN_REG(registers, Rt, NO_PREFER_ZR); + + S32 Rm_sz = _64_BIT; + + if(option & 1) + Rm_s = GET_GEN_REG(AD_RTBL_GEN_64, Rm, PREFER_ZR); + else{ + Rm_s = GET_GEN_REG(AD_RTBL_GEN_32, Rm, PREFER_ZR); + Rm_sz = _32_BIT; + } + + U32 instr_idx = (size << 3) | (V << 2) | opc; + + if(OOB(instr_idx, pre_post_unsigned_register_idx_instr_tbl)) + return 1; + + struct itab instr = pre_post_unsigned_register_idx_instr_tbl[instr_idx]; + + instr_id = instr.instr_id; + + SET_INSTR_ID(out, instr_id); + + if(instr_id != AD_INSTR_PRFM) + ADD_REG_OPERAND(out, Rt, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), registers); + + ADD_REG_OPERAND(out, Rn, sz, NO_PREFER_ZR, _SYSREG(AD_NONE), AD_RTBL_GEN_64); + ADD_REG_OPERAND(out, Rm, Rm_sz, PREFER_ZR, _SYSREG(AD_NONE), Rm_sz == _32_BIT ? + AD_RTBL_GEN_32 : AD_RTBL_GEN_64); + + S32 extended = option != 3; + const char *extend = decode_reg_extend(option); + + if(instr_id == AD_INSTR_PRFM){ + U32 type = bits(Rt, 3, 4); + U32 target = bits(Rt, 1, 2); + U32 policy = Rt & 1; + + const char *types[] = { "PLD", "PLI", "PST" }; + const char *targets[] = { "L1", "L2", "L3" }; + const char *policies[] = { "KEEP", "STRM" }; + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&Rt); + + if(OOB(type, types) || OOB(target, targets) || OOB(policy, policies)) + concat(&DECODE_STR(out), "%s #%#x, [%s, %s", instr.instr_s, Rt, Rn_s, Rm_s); + else{ + concat(&DECODE_STR(out), "%s %s%s%s, [%s, %s", instr.instr_s, types[type], + targets[target], policies[policy], Rn_s, Rm_s); + } + + if(option == 3 && !S) + concat(&DECODE_STR(out), "]"); + else{ + if(option == 3) + concat(&DECODE_STR(out), ", lsl"); + else + concat(&DECODE_STR(out), ", %s", extend); + + if(S){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, 3); + + concat(&DECODE_STR(out), " #3"); + } + + concat(&DECODE_STR(out), "]"); + } + + return 0; + } + + if(!instr.instr_s) + return 1; + + concat(&DECODE_STR(out), "%s %s, [%s, %s", instr.instr_s, Rt_s, Rn_s, Rm_s); + + if(V == 0){ + S32 amount = 0; + + if(instr_id == AD_INSTR_STRB || instr_id == AD_INSTR_LDRB || + instr_id == AD_INSTR_LDRSB){ + if(S == 0){ + if(extended) + concat(&DECODE_STR(out), ", %s", extend); + } + else{ + if(extended){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&S); + concat(&DECODE_STR(out), ", %s #%d", extend, S); + } + else{ + ADD_IMM_OPERAND(out, AD_IMM_UINT, 0); + concat(&DECODE_STR(out), ", lsl #0"); + } + } + + concat(&DECODE_STR(out), "]"); + + return 0; + } + else if(instr_id == AD_INSTR_STR || instr_id == AD_INSTR_LDR){ + if(sz == _64_BIT) + amount = S == 0 ? 0 : 3; + else + amount = S == 0 ? 0 : 2; + } + else if(instr_id == AD_INSTR_LDRSW){ + amount = S == 0 ? 0 : 2; + } + + if(extended){ + concat(&DECODE_STR(out), ", %s", extend); + + if(amount != 0){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&amount); + + concat(&DECODE_STR(out), " #%d", amount); + } + + concat(&DECODE_STR(out), "]"); + } + else{ + if(amount != 0){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&amount); + + concat(&DECODE_STR(out), ", lsl #%d", amount); + } + + concat(&DECODE_STR(out), "]"); + } + } + else{ + /* shift amount for 128 bit */ + S32 amount = 4; + + if(registers == AD_RTBL_FP_8) + amount = S; + else if(registers == AD_RTBL_FP_16) + amount = S == 0 ? 0 : 1; + else if(registers == AD_RTBL_FP_32) + amount = S == 0 ? 0 : 2; + else if(registers == AD_RTBL_FP_64) + amount = S == 0 ? 0 : 3; + + if(registers == AD_RTBL_FP_8){ + if(S == 0){ + if(extended) + concat(&DECODE_STR(out), ", %s", extend); + } + else{ + if(extended){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&amount); + concat(&DECODE_STR(out), ", %s #%d", extend, amount); + } + else{ + ADD_IMM_OPERAND(out, AD_IMM_UINT, 0); + concat(&DECODE_STR(out), ", lsl #0"); + } + } + + concat(&DECODE_STR(out), "]"); + + return 0; + } + + if(extended){ + concat(&DECODE_STR(out), ", %s", extend); + + if(amount != 0){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&amount); + + concat(&DECODE_STR(out), " #%d", amount); + } + + concat(&DECODE_STR(out), "]"); + } + else{ + if(amount != 0){ + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&amount); + + concat(&DECODE_STR(out), ", lsl #%d", amount); + } + + concat(&DECODE_STR(out), "]"); + } + } + + return 0; +} + +static S32 DisassembleLoadAndStorePACInstr(struct instruction *i, + struct ad_insn *out){ + U32 size = bits(i->opcode, 30, 31); + U32 V = bits(i->opcode, 26, 26); + U32 M = bits(i->opcode, 23, 23); + U32 S = bits(i->opcode, 22, 22); + U32 imm9 = bits(i->opcode, 12, 20); + U32 W = bits(i->opcode, 11, 11); + U32 Rn = bits(i->opcode, 5, 9); + U32 Rt = bits(i->opcode, 0, 4); + + if(size != 3) + return 1; + + if(size == 3 && V == 1) + return 1; + + ADD_FIELD(out, size); + ADD_FIELD(out, V); + ADD_FIELD(out, M); + ADD_FIELD(out, S); + ADD_FIELD(out, imm9); + ADD_FIELD(out, W); + ADD_FIELD(out, Rn); + ADD_FIELD(out, Rt); + + S32 instr_id = AD_NONE; + + const char *Rt_s = GET_GEN_REG(AD_RTBL_GEN_64, Rt, NO_PREFER_ZR); + const char *Rn_s = GET_GEN_REG(AD_RTBL_GEN_64, Rn, NO_PREFER_ZR); + + ADD_REG_OPERAND(out, Rt, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), AD_RTBL_GEN_64); + ADD_REG_OPERAND(out, Rn, _SZ(_64_BIT), NO_PREFER_ZR, _SYSREG(AD_NONE), AD_RTBL_GEN_64); + + S32 use_key_A = M == 0; + S32 simm = sign_extend((S << 9) | imm9, 10) << 3; + + concat(&DECODE_STR(out), "ldr"); + + if(M == 0){ + instr_id = AD_INSTR_LDRAA; + concat(&DECODE_STR(out), "aa"); + } + else{ + instr_id = AD_INSTR_LDRAB; + concat(&DECODE_STR(out), "ab"); + } + + concat(&DECODE_STR(out), " %s, [%s", Rt_s, Rn_s); + + if(simm == 0) + concat(&DECODE_STR(out), "]"); + else{ + ADD_IMM_OPERAND(out, AD_IMM_INT, *(S32 *)&simm); + + concat(&DECODE_STR(out), ", #"S_X"]", S_A(simm)); + + if(W == 1) + concat(&DECODE_STR(out), "!"); + } + + SET_INSTR_ID(out, instr_id); + + return 0; +} + +S32 LoadsAndStoresDisassemble(struct instruction *i, struct ad_insn *out){ + S32 result = 0; + + S32 post_pre = 0; + U32 op0 = bits(i->opcode, 28, 31); + U32 op1 = bits(i->opcode, 26, 26); + U32 op2 = bits(i->opcode, 23, 24); + U32 op3 = bits(i->opcode, 16, 21); + U32 op4 = bits(i->opcode, 10, 11); + + if((op0 & ~4) == 0 && op1 == 1 && (op2 == 0 || op2 == 1) && (op3 & ~0x1f) == 0) + { + result = DisassembleLoadStoreMultStructuresInstr(i, out, op2); + post_pre = (op2 != 0) ? POST_INDEXED : 0; + } + else if((op0 & ~4) == 0 && op1 == 1 && (op2 == 2 || op2 == 3)) + { + result = DisassembleLoadStoreSingleStructuresInstr(i, out, op2 != 2); + post_pre = (op2 != 2) ? POST_INDEXED : 0; + } + else if(op0 == 13 && op1 == 0 && (op2 >> 1) == 1 && (op3 >> 5) == 1) + { + result = DisassembleLoadStoreMemoryTagsInstr(i, out); + } + else if((op0 & ~12) == 0 && op1 == 0 && (op2 >> 1) == 0) + { + result = DisassembleLoadAndStoreExclusiveInstr(i, out); + } + else if((op0 & ~12) == 1 && op1 == 0 && (op2 >> 1) == 1 && (op3 & ~0x1f) == 0 && op4 == 0) + { + result = DisassembleLDAPR_STLRInstr(i, out); + } + else if((op0 & ~12) == 1 && (op2 >> 1) == 0) + { + result = DisassembleLoadAndStoreLiteralInstr(i, out); + } + else if((op0 & ~12) == 2 && op2 < 4) + { + result = DisassembleLoadAndStoreRegisterPairInstr(i, out, op2); + post_pre = op2; + } + else if((op0 & ~12) == 3 && (op2 >> 1) == 0){ + if((op3 & ~0x1f) == 0) + { + result = DisassembleLoadAndStoreRegisterInstr(i, out, op4); + post_pre = op4; + } + else{ + if(op4 == 0) + result = DisassembleAtomicMemoryInstr(i, out); + else if(op4 == 2) + result = DisassembleLoadAndStoreRegisterOffsetInstr(i, out); + else if((op4 & 1) == 1) + result = DisassembleLoadAndStorePACInstr(i, out); + else + result = 1; + } + } + else if((op0 & ~12) == 3 && (op2 >> 1) == 1) + result = DisassembleLoadAndStoreRegisterInstr(i, out, UNSIGNED_IMMEDIATE); + else + result = 1; + + out->post_pre_index = post_pre; + + return result; +} diff --git a/src/third_party/armadillo/source/LoadsAndStores.h b/src/third_party/armadillo/source/LoadsAndStores.h new file mode 100644 index 000000000..2b49161dd --- /dev/null +++ b/src/third_party/armadillo/source/LoadsAndStores.h @@ -0,0 +1,18 @@ +#ifndef _LOADSANDSTORES_H_ +#define _LOADSANDSTORES_H_ + +#define NO_ALLOCATE 0 +#define POST_INDEXED 1 +#define OFFSET 2 +#define PRE_INDEXED 3 + +#define UNSIGNED_IMMEDIATE -1 + +#define UNSCALED_IMMEDIATE 0 +#define IMMEDIATE_POST_INDEXED 1 +#define UNPRIVILEGED 2 +#define IMMEDIATE_PRE_INDEXED 3 + +S32 LoadsAndStoresDisassemble(struct instruction *, struct ad_insn *); + +#endif diff --git a/src/third_party/armadillo/source/adefs.h b/src/third_party/armadillo/source/adefs.h new file mode 100644 index 000000000..1864d1e73 --- /dev/null +++ b/src/third_party/armadillo/source/adefs.h @@ -0,0 +1,1626 @@ +#ifndef _ADEFS_H_ +#define _ADEFS_H_ + +struct ad_operand { + /* operand type (AD_OP_*) */ + S32 type; + + /* type == AD_OP_REG */ + struct { + /* register (AD_REG_*) */ + S32 rn; + /* register size */ + S32 sz; + /* is this a floating point register? */ + S32 fp; + /* is this a zero register? */ + S32 zr; + /* if this is a system register, sysreg holds its encoding (AD_SYSREG_*) */ + S32 sysreg; + + /* register string table, use rn for indexing */ + const char **rtbl; + } op_reg; + + /* type == AD_OP_SHIFT */ + struct { + /* shift type (AD_SHIFT_*) */ + S32 type; + /* shift amount */ + S32 amt; + } op_shift; + + /* type == AD_OP_IMM */ + struct { + /* immediate type (AD_IMM_*) */ + S32 type; + /* the bits which make up this immediate */ + S64 bits; + } op_imm; +}; + +struct ad_insn { + /* instruction disassembly */ + char *decoded; + + /* which top level decode group this instruction belongs to (AD_G_*) */ + S32 group; + /* unique instruction ID (AD_INSTR_*) */ + S32 instr_id; + + /* array of decode fields, going from left to right (as per the manual) */ + S32 *fields; + S32 num_fields; + + /* array of ad_operand structs, going from left to right (according to the disassembly) */ + struct ad_operand *operands; + S32 num_operands; + + S32 post_pre_index; + + /* code condition, if any (AD_CC_*) */ + S32 cc; +}; + +static const S32 AD_NONE = -1; + +enum { + AD_OP_REG = 0, AD_OP_IMM, AD_OP_SHIFT, AD_OP_MEM +}; + +enum { + AD_SHIFT_LSL = 0, AD_SHIFT_LSR, AD_SHIFT_ASR, AD_SHIFT_ROR, AD_SHIFT_MSL +}; + +enum { + AD_IMM_INT = 0, AD_IMM_UINT, AD_IMM_LONG, AD_IMM_ULONG, AD_IMM_FLOAT +}; + +enum { + AD_G_Reserved = 0, AD_G_DataProcessingImmediate, AD_G_BranchExcSys, + AD_G_LoadsAndStores, AD_G_DataProcessingRegister, + AD_G_DataProcessingFloatingPoint +}; + +enum { + AD_CC_EQ = 0, AD_CC_NE, AD_CC_CS, AD_CC_CC, AD_CC_MI, AD_CC_PL, + AD_CC_VS, AD_CC_VC, AD_CC_HI, AD_CC_LS, AD_CC_GE, AD_CC_LT, AD_CC_GT, + AD_CC_LE, AD_CC_AL +}; + +enum { + AD_REG_X0 = 0, + AD_REG_X1, + AD_REG_X2, + AD_REG_X3, + AD_REG_X4, + AD_REG_X5, + AD_REG_X6, + AD_REG_X7, + AD_REG_X8, + AD_REG_X9, + AD_REG_X10, + AD_REG_X11, + AD_REG_X12, + AD_REG_X13, + AD_REG_X14, + AD_REG_X15, + AD_REG_X16, + AD_REG_X17, + AD_REG_X18, + AD_REG_X19, + AD_REG_X20, + AD_REG_X21, + AD_REG_X22, + AD_REG_X23, + AD_REG_X24, + AD_REG_X25, + AD_REG_X26, + AD_REG_X27, + AD_REG_X28, + AD_REG_X29, + AD_REG_SP = 30, + AD_REG_XZR = 30 +}; + +enum { + AD_REG_W0 = 0, + AD_REG_W1, + AD_REG_W2, + AD_REG_W3, + AD_REG_W4, + AD_REG_W5, + AD_REG_W6, + AD_REG_W7, + AD_REG_W8, + AD_REG_W9, + AD_REG_W10, + AD_REG_W11, + AD_REG_W12, + AD_REG_W13, + AD_REG_W14, + AD_REG_W15, + AD_REG_W16, + AD_REG_W17, + AD_REG_W18, + AD_REG_W19, + AD_REG_W20, + AD_REG_W21, + AD_REG_W22, + AD_REG_W23, + AD_REG_W24, + AD_REG_W25, + AD_REG_W26, + AD_REG_W27, + AD_REG_W28, + AD_REG_W29, + AD_REG_WSP = 30, + AD_REG_WZR = 30 +}; + +enum { + AD_REG_B0 = 0, + AD_REG_B1, + AD_REG_B2, + AD_REG_B3, + AD_REG_B4, + AD_REG_B5, + AD_REG_B6, + AD_REG_B7, + AD_REG_B8, + AD_REG_B9, + AD_REG_B10, + AD_REG_B11, + AD_REG_B12, + AD_REG_B13, + AD_REG_B14, + AD_REG_B15, + AD_REG_B16, + AD_REG_B17, + AD_REG_B18, + AD_REG_B19, + AD_REG_B20, + AD_REG_B21, + AD_REG_B22, + AD_REG_B23, + AD_REG_B24, + AD_REG_B25, + AD_REG_B26, + AD_REG_B27, + AD_REG_B28, + AD_REG_B29, + AD_REG_B30 +}; + +enum { + AD_REG_H0 = 0, + AD_REG_H1, + AD_REG_H2, + AD_REG_H3, + AD_REG_H4, + AD_REG_H5, + AD_REG_H6, + AD_REG_H7, + AD_REG_H8, + AD_REG_H9, + AD_REG_H10, + AD_REG_H11, + AD_REG_H12, + AD_REG_H13, + AD_REG_H14, + AD_REG_H15, + AD_REG_H16, + AD_REG_H17, + AD_REG_H18, + AD_REG_H19, + AD_REG_H20, + AD_REG_H21, + AD_REG_H22, + AD_REG_H23, + AD_REG_H24, + AD_REG_H25, + AD_REG_H26, + AD_REG_H27, + AD_REG_H28, + AD_REG_H29, + AD_REG_H30 +}; + +enum { + AD_REG_S0 = 0, + AD_REG_S1, + AD_REG_S2, + AD_REG_S3, + AD_REG_S4, + AD_REG_S5, + AD_REG_S6, + AD_REG_S7, + AD_REG_S8, + AD_REG_S9, + AD_REG_S10, + AD_REG_S11, + AD_REG_S12, + AD_REG_S13, + AD_REG_S14, + AD_REG_S15, + AD_REG_S16, + AD_REG_S17, + AD_REG_S18, + AD_REG_S19, + AD_REG_S20, + AD_REG_S21, + AD_REG_S22, + AD_REG_S23, + AD_REG_S24, + AD_REG_S25, + AD_REG_S26, + AD_REG_S27, + AD_REG_S28, + AD_REG_S29, + AD_REG_S30 +}; + +enum { + AD_REG_D0 = 0, + AD_REG_D1, + AD_REG_D2, + AD_REG_D3, + AD_REG_D4, + AD_REG_D5, + AD_REG_D6, + AD_REG_D7, + AD_REG_D8, + AD_REG_D9, + AD_REG_D10, + AD_REG_D11, + AD_REG_D12, + AD_REG_D13, + AD_REG_D14, + AD_REG_D15, + AD_REG_D16, + AD_REG_D17, + AD_REG_D18, + AD_REG_D19, + AD_REG_D20, + AD_REG_D21, + AD_REG_D22, + AD_REG_D23, + AD_REG_D24, + AD_REG_D25, + AD_REG_D26, + AD_REG_D27, + AD_REG_D28, + AD_REG_D29, + AD_REG_D30 +}; + +enum { + AD_REG_Q0 = 0, + AD_REG_Q1, + AD_REG_Q2, + AD_REG_Q3, + AD_REG_Q4, + AD_REG_Q5, + AD_REG_Q6, + AD_REG_Q7, + AD_REG_Q8, + AD_REG_Q9, + AD_REG_Q10, + AD_REG_Q11, + AD_REG_Q12, + AD_REG_Q13, + AD_REG_Q14, + AD_REG_Q15, + AD_REG_Q16, + AD_REG_Q17, + AD_REG_Q18, + AD_REG_Q19, + AD_REG_Q20, + AD_REG_Q21, + AD_REG_Q22, + AD_REG_Q23, + AD_REG_Q24, + AD_REG_Q25, + AD_REG_Q26, + AD_REG_Q27, + AD_REG_Q28, + AD_REG_Q29, + AD_REG_Q30 +}; + +enum { + AD_REG_V0 = 0, + AD_REG_V1, + AD_REG_V2, + AD_REG_V3, + AD_REG_V4, + AD_REG_V5, + AD_REG_V6, + AD_REG_V7, + AD_REG_V8, + AD_REG_V9, + AD_REG_V10, + AD_REG_V11, + AD_REG_V12, + AD_REG_V13, + AD_REG_V14, + AD_REG_V15, + AD_REG_V16, + AD_REG_V17, + AD_REG_V18, + AD_REG_V19, + AD_REG_V20, + AD_REG_V21, + AD_REG_V22, + AD_REG_V23, + AD_REG_V24, + AD_REG_V25, + AD_REG_V26, + AD_REG_V27, + AD_REG_V28, + AD_REG_V29, + AD_REG_V30 +}; + +enum { + AD_INSTR_ADC = 0, + AD_INSTR_ADCS, + AD_INSTR_ADD, + AD_INSTR_ADDG, + AD_INSTR_ADDS, + AD_INSTR_ADR, + AD_INSTR_ADRP, + AD_INSTR_AND, + AD_INSTR_ANDS, + AD_INSTR_ASR, + AD_INSTR_ASRV, + AD_INSTR_AT, + AD_INSTR_AUTDA, + AD_INSTR_AUTDZA, + AD_INSTR_AUTDB, + AD_INSTR_AUTDZB, + AD_INSTR_AUTIA, + AD_INSTR_AUTIZA, + AD_INSTR_AUTIA1716, + AD_INSTR_AUTIASP, + AD_INSTR_AUTIAZ, + AD_INSTR_AUTIB, + AD_INSTR_AUTIZB, + AD_INSTR_AUTIB1716, + AD_INSTR_AUTIBSP, + AD_INSTR_AUTIBZ, + AD_INSTR_AXFLAG, + AD_INSTR_ARM_DDI, + AD_INSTR_B, + AD_INSTR_BFC, + AD_INSTR_BFI, + AD_INSTR_BFM, + AD_INSTR_BFXIL, + AD_INSTR_BIC, + AD_INSTR_BICS, + AD_INSTR_BL, + AD_INSTR_BLR, + AD_INSTR_BLRAAZ, + AD_INSTR_BLRAA, + AD_INSTR_BLRABZ, + AD_INSTR_BLRAB, + AD_INSTR_BR, + AD_INSTR_BRAAZ, + AD_INSTR_BRAA, + AD_INSTR_BRABZ, + AD_INSTR_BRAB, + AD_INSTR_BRK, + AD_INSTR_BTI, + AD_INSTR_CASAB, + AD_INSTR_CASALB, + AD_INSTR_CASB, + AD_INSTR_CASLB, + AD_INSTR_CASAH, + AD_INSTR_CASALH, + AD_INSTR_CASH, + AD_INSTR_CASLH, + AD_INSTR_CASP, + AD_INSTR_CASPA, + AD_INSTR_CASPAL, + AD_INSTR_CASPL, + AD_INSTR_CAS, + AD_INSTR_CASA, + AD_INSTR_CASAL, + AD_INSTR_CASL, + AD_INSTR_CBNZ, + AD_INSTR_CBZ, + AD_INSTR_CCMN, + AD_INSTR_CCMP, + AD_INSTR_CFINV, + AD_INSTR_CFP, + AD_INSTR_CINC, + AD_INSTR_CINV, + AD_INSTR_CLREX, + AD_INSTR_CLS, + AD_INSTR_CLZ, + AD_INSTR_CMN, + AD_INSTR_CMP, + AD_INSTR_CMPP, + AD_INSTR_CNEG, + AD_INSTR_CPP, + AD_INSTR_CRC32B, + AD_INSTR_CRC32H, + AD_INSTR_CRC32W, + AD_INSTR_CRC32X, + AD_INSTR_CRC32CB, + AD_INSTR_CRC32CH, + AD_INSTR_CRC32CW, + AD_INSTR_CRC32CX, + AD_INSTR_CSDB, + AD_INSTR_CSEL, + AD_INSTR_CSET, + AD_INSTR_CSETM, + AD_INSTR_CSINC, + AD_INSTR_CSINV, + AD_INSTR_CSNEG, + AD_INSTR_DC, + AD_INSTR_DCPS1, + AD_INSTR_DCPS2, + AD_INSTR_DCPS3, + AD_INSTR_DMB, + AD_INSTR_DRPS, + AD_INSTR_DSB, + AD_INSTR_DVP, + AD_INSTR_EON, + AD_INSTR_EOR, + AD_INSTR_ERET, + AD_INSTR_ERETAA, + AD_INSTR_ERETAB, + AD_INSTR_ESB, + AD_INSTR_EXTR, + AD_INSTR_GMI, + AD_INSTR_HINT, + AD_INSTR_HLT, + AD_INSTR_HVC, + AD_INSTR_IC, + AD_INSTR_IRG, + AD_INSTR_ISB, + AD_INSTR_LDADDAB, + AD_INSTR_LDADDALB, + AD_INSTR_LDADDB, + AD_INSTR_LDADDLB, + AD_INSTR_LDADDAH, + AD_INSTR_LDADDALH, + AD_INSTR_LDADDH, + AD_INSTR_LDADDLH, + AD_INSTR_LDADD, + AD_INSTR_LDADDA, + AD_INSTR_LDADDAL, + AD_INSTR_LDADDL, + AD_INSTR_LDAPR, + AD_INSTR_LDAPRB, + AD_INSTR_LDAPRH, + AD_INSTR_LDAPUR, + AD_INSTR_LDAPURB, + AD_INSTR_LDAPURH, + AD_INSTR_LDAPURSB, + AD_INSTR_LDAPURSH, + AD_INSTR_LDAPURSW, + AD_INSTR_LDAR, + AD_INSTR_LDARB, + AD_INSTR_LDARH, + AD_INSTR_LDAXP, + AD_INSTR_LDAXR, + AD_INSTR_LDAXRB, + AD_INSTR_LDAXRH, + AD_INSTR_LDCLRAB, + AD_INSTR_LDCLRALB, + AD_INSTR_LDCLRB, + AD_INSTR_LDCLRLB, + AD_INSTR_LDCLRAH, + AD_INSTR_LDCLRALH, + AD_INSTR_LDCLRH, + AD_INSTR_LDCLRLH, + AD_INSTR_LDCLR, + AD_INSTR_LDCLRA, + AD_INSTR_LDCLRAL, + AD_INSTR_LDCLRL, + AD_INSTR_LDEORAB, + AD_INSTR_LDEORALB, + AD_INSTR_LDEORB, + AD_INSTR_LDEORLB, + AD_INSTR_LDEORAH, + AD_INSTR_LDEORALH, + AD_INSTR_LDEORH, + AD_INSTR_LDEORLH, + AD_INSTR_LDEOR, + AD_INSTR_LDEORA, + AD_INSTR_LDEORAL, + AD_INSTR_LDEORL, + AD_INSTR_LDG, + AD_INSTR_LDGM, + AD_INSTR_LDLARB, + AD_INSTR_LDLARH, + AD_INSTR_LDLAR, + AD_INSTR_LDNP, + AD_INSTR_LDP, + AD_INSTR_LDPSW, + AD_INSTR_LDR, + AD_INSTR_LDRAA, + AD_INSTR_LDRAB, + AD_INSTR_LDRB, + AD_INSTR_LDRH, + AD_INSTR_LDRSB, + AD_INSTR_LDRSH, + AD_INSTR_LDRSW, + AD_INSTR_LDSETAB, + AD_INSTR_LDSETALB, + AD_INSTR_LDSETB, + AD_INSTR_LDSETLB, + AD_INSTR_LDSETAH, + AD_INSTR_LDSETALH, + AD_INSTR_LDSETH, + AD_INSTR_LDSETLH, + AD_INSTR_LDSET, + AD_INSTR_LDSETA, + AD_INSTR_LDSETAL, + AD_INSTR_LDSETL, + AD_INSTR_LDSMAXAB, + AD_INSTR_LDSMAXALB, + AD_INSTR_LDSMAXB, + AD_INSTR_LDSMAXLB, + AD_INSTR_LDSMAXAH, + AD_INSTR_LDSMAXALH, + AD_INSTR_LDSMAXH, + AD_INSTR_LDSMAXLH, + AD_INSTR_LDSMAX, + AD_INSTR_LDSMAXA, + AD_INSTR_LDSMAXAL, + AD_INSTR_LDSMAXL, + AD_INSTR_LDSMINAB, + AD_INSTR_LDSMINALB, + AD_INSTR_LDSMINB, + AD_INSTR_LDSMINLB, + AD_INSTR_LDSMINAH, + AD_INSTR_LDSMINALH, + AD_INSTR_LDSMINH, + AD_INSTR_LDSMINLH, + AD_INSTR_LDSMIN, + AD_INSTR_LDSMINA, + AD_INSTR_LDSMINAL, + AD_INSTR_LDSMINL, + AD_INSTR_LDTR, + AD_INSTR_LDTRB, + AD_INSTR_LDTRH, + AD_INSTR_LDTRSB, + AD_INSTR_LDTRSH, + AD_INSTR_LDTRSW, + AD_INSTR_LDUMAXAB, + AD_INSTR_LDUMAXALB, + AD_INSTR_LDUMAXB, + AD_INSTR_LDUMAXLB, + AD_INSTR_LDUMAXAH, + AD_INSTR_LDUMAXALH, + AD_INSTR_LDUMAXH, + AD_INSTR_LDUMAXLH, + AD_INSTR_LDUMAX, + AD_INSTR_LDUMAXA, + AD_INSTR_LDUMAXAL, + AD_INSTR_LDUMAXL, + AD_INSTR_LDUMINAB, + AD_INSTR_LDUMINALB, + AD_INSTR_LDUMINB, + AD_INSTR_LDUMINLB, + AD_INSTR_LDUMINAH, + AD_INSTR_LDUMINALH, + AD_INSTR_LDUMINH, + AD_INSTR_LDUMINLH, + AD_INSTR_LDUMIN, + AD_INSTR_LDUMINA, + AD_INSTR_LDUMINAL, + AD_INSTR_LDUMINL, + AD_INSTR_LDUR, + AD_INSTR_LDURB, + AD_INSTR_LDURH, + AD_INSTR_LDURSB, + AD_INSTR_LDURSH, + AD_INSTR_LDURSW, + AD_INSTR_LDXP, + AD_INSTR_LDXR, + AD_INSTR_LDXRB, + AD_INSTR_LDXRH, + AD_INSTR_LSL, + AD_INSTR_LSLV, + AD_INSTR_LSR, + AD_INSTR_LSRV, + AD_INSTR_MADD, + AD_INSTR_MNEG, + AD_INSTR_MOV, + AD_INSTR_MOVK, + AD_INSTR_MOVN, + AD_INSTR_MOVZ, + AD_INSTR_MRS, + AD_INSTR_MSR, + AD_INSTR_MSUB, + AD_INSTR_MUL, + AD_INSTR_MVN, + AD_INSTR_NEG, + AD_INSTR_NEGS, + AD_INSTR_NGC, + AD_INSTR_NGCS, + AD_INSTR_NOP, + AD_INSTR_ORN, + AD_INSTR_ORR, + AD_INSTR_PACDA, + AD_INSTR_PACDZA, + AD_INSTR_PACDB, + AD_INSTR_PACDZB, + AD_INSTR_PACGA, + AD_INSTR_PACIA, + AD_INSTR_PACIZA, + AD_INSTR_PACIA1716, + AD_INSTR_PACIASP, + AD_INSTR_PACIAZ, + AD_INSTR_PACIB, + AD_INSTR_PACIZB, + AD_INSTR_PACIB1716, + AD_INSTR_PACIBSP, + AD_INSTR_PACIBZ, + AD_INSTR_PRFM, + AD_INSTR_PRFUM, + AD_INSTR_PSB_CSYNC, + AD_INSTR_PSSBB, + AD_INSTR_RBIT, + AD_INSTR_RET, + AD_INSTR_RETAA, + AD_INSTR_RETAB, + AD_INSTR_REV, + AD_INSTR_REV16, + AD_INSTR_REV32, + AD_INSTR_REV64, + AD_INSTR_RMIF, + AD_INSTR_ROR, + AD_INSTR_RORV, + AD_INSTR_SB, + AD_INSTR_SBC, + AD_INSTR_SBCS, + AD_INSTR_SBFIZ, + AD_INSTR_SBFM, + AD_INSTR_SBFX, + AD_INSTR_SDIV, + AD_INSTR_SETF8, + AD_INSTR_SETF16, + AD_INSTR_SEV, + AD_INSTR_SEVL, + AD_INSTR_SMADDL, + AD_INSTR_SMC, + AD_INSTR_SMNEGL, + AD_INSTR_SMSUBL, + AD_INSTR_SMULH, + AD_INSTR_SMULL, + AD_INSTR_SSBB, + AD_INSTR_ST2G, + AD_INSTR_STADDB, + AD_INSTR_STADDLB, + AD_INSTR_STADDH, + AD_INSTR_STADDLH, + AD_INSTR_STADD, + AD_INSTR_STADDL, + AD_INSTR_STCLRB, + AD_INSTR_STCLRLB, + AD_INSTR_STCLRH, + AD_INSTR_STCLRLH, + AD_INSTR_STCLR, + AD_INSTR_STCLRL, + AD_INSTR_STEORB, + AD_INSTR_STEORLB, + AD_INSTR_STEORH, + AD_INSTR_STEORLH, + AD_INSTR_STEOR, + AD_INSTR_STEORL, + AD_INSTR_STG, + AD_INSTR_STGM, + AD_INSTR_STGP, + AD_INSTR_STLLRB, + AD_INSTR_STLLRH, + AD_INSTR_STLLR, + AD_INSTR_STLR, + AD_INSTR_STLRB, + AD_INSTR_STLRH, + AD_INSTR_STLUR, + AD_INSTR_STLURB, + AD_INSTR_STLURH, + AD_INSTR_STLXP, + AD_INSTR_STLXR, + AD_INSTR_STLXRB, + AD_INSTR_STLXRH, + AD_INSTR_STNP, + AD_INSTR_STP, + AD_INSTR_STR, + AD_INSTR_STRB, + AD_INSTR_STRH, + AD_INSTR_STSETB, + AD_INSTR_STSETLB, + AD_INSTR_STSETH, + AD_INSTR_STSETLH, + AD_INSTR_STSET, + AD_INSTR_STSETL, + AD_INSTR_STSMAXB, + AD_INSTR_STSMAXLB, + AD_INSTR_STSMAXH, + AD_INSTR_STSMAXLH, + AD_INSTR_STSMAX, + AD_INSTR_STSMAXL, + AD_INSTR_STSMINB, + AD_INSTR_STSMINLB, + AD_INSTR_STSMINH, + AD_INSTR_STSMINLH, + AD_INSTR_STSMIN, + AD_INSTR_STSMINL, + AD_INSTR_STTR, + AD_INSTR_STTRB, + AD_INSTR_STTRH, + AD_INSTR_STUMAXB, + AD_INSTR_STUMAXLB, + AD_INSTR_STUMAXH, + AD_INSTR_STUMAXLH, + AD_INSTR_STUMAX, + AD_INSTR_STUMAXL, + AD_INSTR_STUMINB, + AD_INSTR_STUMINLB, + AD_INSTR_STUMINH, + AD_INSTR_STUMINLH, + AD_INSTR_STUMIN, + AD_INSTR_STUMINL, + AD_INSTR_STUR, + AD_INSTR_STURB, + AD_INSTR_STURH, + AD_INSTR_STXP, + AD_INSTR_STXR, + AD_INSTR_STXRB, + AD_INSTR_STXRH, + AD_INSTR_STZ2G, + AD_INSTR_STZG, + AD_INSTR_STZGM, + AD_INSTR_SUB, + AD_INSTR_SUBG, + AD_INSTR_SUBP, + AD_INSTR_SUBPS, + AD_INSTR_SUBS, + AD_INSTR_SVC, + AD_INSTR_SWPAB, + AD_INSTR_SWPALB, + AD_INSTR_SWPB, + AD_INSTR_SWPLB, + AD_INSTR_SWPAH, + AD_INSTR_SWPALH, + AD_INSTR_SWPH, + AD_INSTR_SWPLH, + AD_INSTR_SWP, + AD_INSTR_SWPA, + AD_INSTR_SWPAL, + AD_INSTR_SWPL, + AD_INSTR_SXTB, + AD_INSTR_SXTH, + AD_INSTR_SXTW, + AD_INSTR_SYS, + AD_INSTR_SYSL, + AD_INSTR_TBNZ, + AD_INSTR_TBZ, + AD_INSTR_TLBI, + AD_INSTR_TSB_CSYNC, + AD_INSTR_TST, + AD_INSTR_UBFIZ, + AD_INSTR_UBFM, + AD_INSTR_UBFX, + AD_INSTR_UDF, + AD_INSTR_UDIV, + AD_INSTR_UMADDL, + AD_INSTR_UMNEGL, + AD_INSTR_UMSUBL, + AD_INSTR_UMULH, + AD_INSTR_UMULL, + AD_INSTR_UXTB, + AD_INSTR_UXTH, + AD_INSTR_WFE, + AD_INSTR_WFI, + AD_INSTR_XAFLAG, + AD_INSTR_XPACD, + AD_INSTR_XPACI, + AD_INSTR_XPACLRI, + AD_INSTR_YIELD, + AD_INSTR_ABS, + AD_INSTR_ADDHN, + AD_INSTR_ADDHN2, + AD_INSTR_ADDP, + AD_INSTR_ADDV, + AD_INSTR_AESD, + AD_INSTR_AESE, + AD_INSTR_AESIMC, + AD_INSTR_AESMC, + AD_INSTR_BCAX, + AD_INSTR_BIF, + AD_INSTR_BIT, + AD_INSTR_BSL, + AD_INSTR_CMEQ, + AD_INSTR_CMGE, + AD_INSTR_CMGT, + AD_INSTR_CMHI, + AD_INSTR_CMHS, + AD_INSTR_CMLE, + AD_INSTR_CMLT, + AD_INSTR_CMTST, + AD_INSTR_CNT, + AD_INSTR_DUP, + AD_INSTR_EOR3, + AD_INSTR_EXT, + AD_INSTR_FABD, + AD_INSTR_FABS, + AD_INSTR_FACGE, + AD_INSTR_FACGT, + AD_INSTR_FADD, + AD_INSTR_FADDP, + AD_INSTR_FCADD, + AD_INSTR_FCCMP, + AD_INSTR_FCCMPE, + AD_INSTR_FCMEQ, + AD_INSTR_FCMGE, + AD_INSTR_FCMGT, + AD_INSTR_FCMLA, + AD_INSTR_FCMLE, + AD_INSTR_FCMLT, + AD_INSTR_FCMP, + AD_INSTR_FCMPE, + AD_INSTR_FCSEL, + AD_INSTR_FCVT, + AD_INSTR_FCVTAS, + AD_INSTR_FCVTAU, + AD_INSTR_FCVTL, + AD_INSTR_FCVTL2, + AD_INSTR_FCVTMS, + AD_INSTR_FCVTMU, + AD_INSTR_FCVTN, + AD_INSTR_FCVTN2, + AD_INSTR_FCVTNS, + AD_INSTR_FCVTNU, + AD_INSTR_FCVTPS, + AD_INSTR_FCVTPU, + AD_INSTR_FCVTXN, + AD_INSTR_FCVTXN2, + AD_INSTR_FCVTZS, + AD_INSTR_FCVTZU, + AD_INSTR_FDIV, + AD_INSTR_FJCVTZS, + AD_INSTR_FMADD, + AD_INSTR_FMAX, + AD_INSTR_FMAXNM, + AD_INSTR_FMAXNMP, + AD_INSTR_FMAXNMV, + AD_INSTR_FMAXP, + AD_INSTR_FMAXV, + AD_INSTR_FMIN, + AD_INSTR_FMINNM, + AD_INSTR_FMINNMP, + AD_INSTR_FMINNMV, + AD_INSTR_FMINP, + AD_INSTR_FMINV, + AD_INSTR_FMLA, + AD_INSTR_FMLAL, + AD_INSTR_FMLAL2, + AD_INSTR_FMLS, + AD_INSTR_FMLSL, + AD_INSTR_FMLSL2, + AD_INSTR_FMOV, + AD_INSTR_FMSUB, + AD_INSTR_FMUL, + AD_INSTR_FMULX, + AD_INSTR_FNEG, + AD_INSTR_FNMADD, + AD_INSTR_FNMSUB, + AD_INSTR_FNMUL, + AD_INSTR_FRECPE, + AD_INSTR_FRECPS, + AD_INSTR_FRECPX, + AD_INSTR_FRINT32X, + AD_INSTR_FRINT32Z, + AD_INSTR_FRINT64X, + AD_INSTR_FRINT64Z, + AD_INSTR_FRINTA, + AD_INSTR_FRINTI, + AD_INSTR_FRINTM, + AD_INSTR_FRINTN, + AD_INSTR_FRINTP, + AD_INSTR_FRINTX, + AD_INSTR_FRINTZ, + AD_INSTR_FRSQRTE, + AD_INSTR_FRSQRTS, + AD_INSTR_FSQRT, + AD_INSTR_FSUB, + AD_INSTR_INS, + AD_INSTR_LD1, + AD_INSTR_LD1R, + AD_INSTR_LD2, + AD_INSTR_LD2R, + AD_INSTR_LD3, + AD_INSTR_LD3R, + AD_INSTR_LD4, + AD_INSTR_LD4R, + AD_INSTR_MLA, + AD_INSTR_MLS, + AD_INSTR_MOVI, + AD_INSTR_MVNI, + AD_INSTR_NOT, + AD_INSTR_PMUL, + AD_INSTR_PMULL, + AD_INSTR_PMULL2, + AD_INSTR_RADDHN, + AD_INSTR_RADDHN2, + AD_INSTR_RAX1, + AD_INSTR_RSHRN, + AD_INSTR_RSHRN2, + AD_INSTR_RSUBHN, + AD_INSTR_RSUBHN2, + AD_INSTR_SABA, + AD_INSTR_SABAL, + AD_INSTR_SABAL2, + AD_INSTR_SABD, + AD_INSTR_SABDL, + AD_INSTR_SABDL2, + AD_INSTR_SADALP, + AD_INSTR_SADDL, + AD_INSTR_SADDL2, + AD_INSTR_SADDLP, + AD_INSTR_SADDLV, + AD_INSTR_SADDW, + AD_INSTR_SADDW2, + AD_INSTR_SCVTF, + AD_INSTR_SDOT, + AD_INSTR_SHA1C, + AD_INSTR_SHA1H, + AD_INSTR_SHA1M, + AD_INSTR_SHA1P, + AD_INSTR_SHA1SU0, + AD_INSTR_SHA1SU1, + AD_INSTR_SHA256H2, + AD_INSTR_SHA256H, + AD_INSTR_SHA256SU0, + AD_INSTR_SHA256SU1, + AD_INSTR_SHA512H, + AD_INSTR_SHA512H2, + AD_INSTR_SHA512SU0, + AD_INSTR_SHA512SU1, + AD_INSTR_SHADD, + AD_INSTR_SHL, + AD_INSTR_SHLL, + AD_INSTR_SHLL2, + AD_INSTR_SHRN, + AD_INSTR_SHRN2, + AD_INSTR_SHSUB, + AD_INSTR_SLI, + AD_INSTR_SM3PARTW1, + AD_INSTR_SM3PARTW2, + AD_INSTR_SM3SS1, + AD_INSTR_SM3TT1A, + AD_INSTR_SM3TT1B, + AD_INSTR_SM3TT2A, + AD_INSTR_SM3TT2B, + AD_INSTR_SM4E, + AD_INSTR_SM4EKEY, + AD_INSTR_SMAX, + AD_INSTR_SMAXP, + AD_INSTR_SMAXV, + AD_INSTR_SMIN, + AD_INSTR_SMINP, + AD_INSTR_SMINV, + AD_INSTR_SMLAL, + AD_INSTR_SMLAL2, + AD_INSTR_SMLSL, + AD_INSTR_SMLSL2, + AD_INSTR_SMOV, + AD_INSTR_SMULL2, + AD_INSTR_SQABS, + AD_INSTR_SQADD, + AD_INSTR_SQDMLAL, + AD_INSTR_SQDMLAL2, + AD_INSTR_SQDMLSL, + AD_INSTR_SQDMLSL2, + AD_INSTR_SQDMULH, + AD_INSTR_SQDMULL, + AD_INSTR_SQDMULL2, + AD_INSTR_SQNEG, + AD_INSTR_SQRDMLAH, + AD_INSTR_SQRDMLSH, + AD_INSTR_SQRDMULH, + AD_INSTR_SQRSHL, + AD_INSTR_SQRSHRN, + AD_INSTR_SQRSHRN2, + AD_INSTR_SQRSHRUN, + AD_INSTR_SQRSHRUN2, + AD_INSTR_SQSHL, + AD_INSTR_SQSHLU, + AD_INSTR_SQSHRN, + AD_INSTR_SQSHRN2, + AD_INSTR_SQSHRUN, + AD_INSTR_SQSHRUN2, + AD_INSTR_SQSUB, + AD_INSTR_SQXTN, + AD_INSTR_SQXTN2, + AD_INSTR_SQXTUN, + AD_INSTR_SQXTUN2, + AD_INSTR_SRHADD, + AD_INSTR_SRI, + AD_INSTR_SRSHL, + AD_INSTR_SRSHR, + AD_INSTR_SRSRA, + AD_INSTR_SSHL, + AD_INSTR_SSHLL, + AD_INSTR_SSHLL2, + AD_INSTR_SSHR, + AD_INSTR_SSRA, + AD_INSTR_SSUBL, + AD_INSTR_SSUBL2, + AD_INSTR_SSUBW, + AD_INSTR_SSUBW2, + AD_INSTR_ST1, + AD_INSTR_ST2, + AD_INSTR_ST3, + AD_INSTR_ST4, + AD_INSTR_SUBHN, + AD_INSTR_SUBHN2, + AD_INSTR_SUQADD, + AD_INSTR_SXTL, + AD_INSTR_SXTL2, + AD_INSTR_TBL, + AD_INSTR_TBX, + AD_INSTR_TRN1, + AD_INSTR_TRN2, + AD_INSTR_UABA, + AD_INSTR_UABAL, + AD_INSTR_UABAL2, + AD_INSTR_UABD, + AD_INSTR_UABDL, + AD_INSTR_UABDL2, + AD_INSTR_UADALP, + AD_INSTR_UADDL, + AD_INSTR_UADDL2, + AD_INSTR_UADDLP, + AD_INSTR_UADDLV, + AD_INSTR_UADDW, + AD_INSTR_UADDW2, + AD_INSTR_UCVTF, + AD_INSTR_UDOT, + AD_INSTR_UHADD, + AD_INSTR_UHSUB, + AD_INSTR_UMAX, + AD_INSTR_UMAXP, + AD_INSTR_UMAXV, + AD_INSTR_UMIN, + AD_INSTR_UMINP, + AD_INSTR_UMINV, + AD_INSTR_UMLAL, + AD_INSTR_UMLAL2, + AD_INSTR_UMLSL, + AD_INSTR_UMLSL2, + AD_INSTR_UMOV, + AD_INSTR_UMULL2, + AD_INSTR_UQADD, + AD_INSTR_UQRSHL, + AD_INSTR_UQRSHRN, + AD_INSTR_UQRSHRN2, + AD_INSTR_UQSHL, + AD_INSTR_UQSHRN, + AD_INSTR_UQSHRN2, + AD_INSTR_UQSUB, + AD_INSTR_UQXTN, + AD_INSTR_UQXTN2, + AD_INSTR_URECPE, + AD_INSTR_URHADD, + AD_INSTR_URSHL, + AD_INSTR_URSHR, + AD_INSTR_URSQRTE, + AD_INSTR_URSRA, + AD_INSTR_USHL, + AD_INSTR_USHLL, + AD_INSTR_USHLL2, + AD_INSTR_USHR, + AD_INSTR_USQADD, + AD_INSTR_USRA, + AD_INSTR_USUBL, + AD_INSTR_USUBL2, + AD_INSTR_USUBW, + AD_INSTR_USUBW2, + AD_INSTR_UXTL, + AD_INSTR_UXTL2, + AD_INSTR_UZP1, + AD_INSTR_UZP2, + AD_INSTR_XAR, + AD_INSTR_XTN, + AD_INSTR_XTN2, + AD_INSTR_ZIP1, + AD_INSTR_ZIP2, +}; + +enum { + AD_SYSREG_ACTLR_EL1 = 0xc081, + AD_SYSREG_ACTLR_EL2 = 0xe081, + AD_SYSREG_ACTLR_EL3 = 0xf081, + AD_SYSREG_AFSR0_EL1 = 0xc288, + AD_SYSREG_AFSR0_EL12 = 0xea88, + AD_SYSREG_AFSR0_EL2 = 0xe288, + AD_SYSREG_AFSR0_EL3 = 0xf288, + AD_SYSREG_AFSR1_EL1 = 0xc289, + AD_SYSREG_AFSR1_EL12 = 0xea89, + AD_SYSREG_AFSR1_EL2 = 0xe289, + AD_SYSREG_AFSR1_EL3 = 0xf289, + AD_SYSREG_AIDR_EL1 = 0xc807, + AD_SYSREG_AMAIR_EL1 = 0xc518, + AD_SYSREG_AMAIR_EL12 = 0xed18, + AD_SYSREG_AMAIR_EL2 = 0xe518, + AD_SYSREG_AMAIR_EL3 = 0xf518, + AD_SYSREG_AMCFGR_EL0 = 0xde91, + AD_SYSREG_AMCGCR_EL0 = 0xde92, + AD_SYSREG_AMCNTENCLR0_EL0 = 0xde94, + AD_SYSREG_AMCNTENCLR1_EL0 = 0xde98, + AD_SYSREG_AMCNTENSET0_EL0 = 0xde95, + AD_SYSREG_AMCNTENSET1_EL0 = 0xde99, + AD_SYSREG_AMCR_EL0 = 0xde90, + AD_SYSREG_AMUSERENR_EL0 = 0xde93, + AD_SYSREG_APDAKeyHi_EL1 = 0xc111, + AD_SYSREG_APDAKeyLo_EL1 = 0xc110, + AD_SYSREG_APDBKeyHi_EL1 = 0xc113, + AD_SYSREG_APDBKeyLo_EL1 = 0xc112, + AD_SYSREG_APGAKeyHi_EL1 = 0xc119, + AD_SYSREG_APGAKeyLo_EL1 = 0xc118, + AD_SYSREG_APIAKeyHi_EL1 = 0xc109, + AD_SYSREG_APIAKeyLo_EL1 = 0xc108, + AD_SYSREG_APIBKeyHi_EL1 = 0xc10b, + AD_SYSREG_APIBKeyLo_EL1 = 0xc10a, + AD_SYSREG_CCSIDR2_EL1 = 0xc802, + AD_SYSREG_CCSIDR_EL1 = 0xc800, + AD_SYSREG_CLIDR_EL1 = 0xc801, + AD_SYSREG_CNTFRQ_EL0 = 0xdf00, + AD_SYSREG_CNTHCTL_EL2 = 0xe708, + AD_SYSREG_CNTHPS_CTL_EL2 = 0xe729, + AD_SYSREG_CNTHPS_CVAL_EL2 = 0xe72a, + AD_SYSREG_CNTHPS_TVAL_EL2 = 0xe728, + AD_SYSREG_CNTHP_CTL_EL2 = 0xe711, + AD_SYSREG_CNTHP_CVAL_EL2 = 0xe712, + AD_SYSREG_CNTHP_TVAL_EL2 = 0xe710, + AD_SYSREG_CNTHVS_CTL_EL2 = 0xe721, + AD_SYSREG_CNTHVS_CVAL_EL2 = 0xe722, + AD_SYSREG_CNTHVS_TVAL_EL2 = 0xe720, + AD_SYSREG_CNTHV_CTL_EL2 = 0xe719, + AD_SYSREG_CNTHV_CVAL_EL2 = 0xe71a, + AD_SYSREG_CNTHV_TVAL_EL2 = 0xe718, + AD_SYSREG_CNTKCTL_EL1 = 0xc708, + AD_SYSREG_CNTKCTL_EL12 = 0xc708, + AD_SYSREG_CNTPCT_EL0 = 0xdf01, + AD_SYSREG_CNTPS_CTL_EL1 = 0xff11, + AD_SYSREG_CNTPS_CVAL_EL1 = 0xff12, + AD_SYSREG_CNTPS_TVAL_EL1 = 0xff10, + AD_SYSREG_CNTP_CTL_EL0 = 0xdf11, + AD_SYSREG_CNTP_CTL_EL02 = 0xef11, + AD_SYSREG_CNTP_CVAL_EL0 = 0xdf12, + AD_SYSREG_CNTP_CVAL_EL02 = 0xef12, + AD_SYSREG_CNTP_TVAL_EL0 = 0xdf10, + AD_SYSREG_CNTP_TVAL_EL02 = 0xef10, + AD_SYSREG_CNTVCT_EL0 = 0xdf02, + AD_SYSREG_CNTVOFF_EL2 = 0xe703, + AD_SYSREG_CNTV_CTL_EL0 = 0xdf19, + AD_SYSREG_CNTV_CTL_EL02 = 0xef19, + AD_SYSREG_CNTV_CVAL_EL0 = 0xdf1a, + AD_SYSREG_CNTV_CVAL_EL02 = 0xef1a, + AD_SYSREG_CNTV_TVAL_EL0 = 0xdf18, + AD_SYSREG_CNTV_TVAL_EL02 = 0xef18, + AD_SYSREG_CONTEXTIDR_EL1 = 0xc681, + AD_SYSREG_CONTEXTIDR_EL12 = 0xee81, + AD_SYSREG_CONTEXTIDR_EL2 = 0xe681, + AD_SYSREG_CPACR_EL1 = 0xc082, + AD_SYSREG_CPACR_EL12 = 0xe882, + AD_SYSREG_CPTR_EL2 = 0xe08a, + AD_SYSREG_CPTR_EL3 = 0xf08a, + AD_SYSREG_CSSELR_EL1 = 0xd000, + AD_SYSREG_CTR_EL0 = 0xd801, + AD_SYSREG_CurrentEL = 0xc212, + AD_SYSREG_DACR32_EL2 = 0xe180, + AD_SYSREG_DAIF = 0xda11, + AD_SYSREG_DBGAUTHSTATUS_EL1 = 0x83f6, + AD_SYSREG_DBGCLAIMCLR_EL1 = 0x83ce, + AD_SYSREG_DBGCLAIMSET_EL1 = 0x83c6, + AD_SYSREG_DBGDTRRX_EL0 = 0x9828, + AD_SYSREG_DBGDTRTX_EL0 = 0x9828, + AD_SYSREG_DBGDTR_EL0 = 0x9820, + AD_SYSREG_DBGPRCR_EL1 = 0x80a4, + AD_SYSREG_DBGVCR32_EL2 = 0xa038, + AD_SYSREG_DCZID_EL0 = 0xd807, + AD_SYSREG_DISR_EL1 = 0xc609, + AD_SYSREG_DIT = 0xda15, + AD_SYSREG_DLR_EL0 = 0xda29, + AD_SYSREG_DSPSR_EL0 = 0xda28, + AD_SYSREG_ELR_EL1 = 0xc201, + AD_SYSREG_ELR_EL12 = 0xea01, + AD_SYSREG_ELR_EL2 = 0xe201, + AD_SYSREG_ELR_EL3 = 0xf201, + AD_SYSREG_ERRIDR_EL1 = 0xc298, + AD_SYSREG_ERRSELR_EL1 = 0xc299, + AD_SYSREG_ERXADDR_EL1 = 0xc2a3, + AD_SYSREG_ERXCTLR_EL1 = 0xc2a1, + AD_SYSREG_ERXFR_EL1 = 0xc2a0, + AD_SYSREG_ERXMISC0_EL1 = 0xc2a8, + AD_SYSREG_ERXMISC1_EL1 = 0xc2a9, + AD_SYSREG_ERXMISC2_EL1 = 0xc2aa, + AD_SYSREG_ERXMISC3_EL1 = 0xc2ab, + AD_SYSREG_ERXPFGCDN_EL1 = 0xc2a6, + AD_SYSREG_ERXPFGCTL_EL1 = 0xc2a5, + AD_SYSREG_ERXPFGF_EL1 = 0xc2a4, + AD_SYSREG_ERXSTATUS_EL1 = 0xc2a2, + AD_SYSREG_ESR_EL1 = 0xc290, + AD_SYSREG_ESR_EL12 = 0xea90, + AD_SYSREG_ESR_EL2 = 0xe290, + AD_SYSREG_ESR_EL3 = 0xf290, + AD_SYSREG_FAR_EL1 = 0xc300, + AD_SYSREG_FAR_EL12 = 0xeb00, + AD_SYSREG_FAR_EL2 = 0xe300, + AD_SYSREG_FAR_EL3 = 0xf300, + AD_SYSREG_FPCR = 0xd184, + AD_SYSREG_FPEXC32_EL2 = 0xe298, + AD_SYSREG_FPSR = 0xd194, + AD_SYSREG_GCR_EL1 = 0xc086, + AD_SYSREG_GMID_EL1 = 0xcc0, + AD_SYSREG_HACR_EL2 = 0xe08f, + AD_SYSREG_HCR_EL2 = 0xe088, + AD_SYSREG_HPFAR_EL2 = 0xe304, + AD_SYSREG_HSTR_EL2 = 0xe08b, + AD_SYSREG_ID_AA64AFR0_EL1 = 0xc02c, + AD_SYSREG_ID_AA64AFR1_EL1 = 0xc02d, + AD_SYSREG_ID_AA64DFR0_EL1 = 0xc028, + AD_SYSREG_ID_AA64DFR1_EL1 = 0xc029, + AD_SYSREG_ID_AA64ISAR0_EL1 = 0xc030, + AD_SYSREG_ID_AA64ISAR1_EL1 = 0xc031, + AD_SYSREG_ID_AA64MMFR0_EL1 = 0xc038, + AD_SYSREG_ID_AA64MMFR1_EL1 = 0xc039, + AD_SYSREG_ID_AA64MMFR2_EL1 = 0xc03a, + AD_SYSREG_ID_AA64PFR0_EL1 = 0xc020, + AD_SYSREG_ID_AA64PFR1_EL1 = 0xc021, + AD_SYSREG_ID_AFR0_EL1 = 0xc00b, + AD_SYSREG_ID_DFR0_EL1 = 0xc00a, + AD_SYSREG_ID_ISAR0_EL1 = 0xc010, + AD_SYSREG_ID_ISAR1_EL1 = 0xc011, + AD_SYSREG_ID_ISAR2_EL1 = 0xc012, + AD_SYSREG_ID_ISAR3_EL1 = 0xc013, + AD_SYSREG_ID_ISAR4_EL1 = 0xc014, + AD_SYSREG_ID_ISAR5_EL1 = 0xc015, + AD_SYSREG_ID_ISAR6_EL1 = 0xc017, + AD_SYSREG_ID_MMFR0_EL1 = 0xc00c, + AD_SYSREG_ID_MMFR1_EL1 = 0xc00d, + AD_SYSREG_ID_MMFR2_EL1 = 0xc00e, + AD_SYSREG_ID_MMFR3_EL1 = 0xc00f, + AD_SYSREG_ID_MMFR4_EL1 = 0xc016, + AD_SYSREG_ID_PFR0_EL1 = 0xc008, + AD_SYSREG_ID_PFR1_EL1 = 0xc009, + AD_SYSREG_ID_PFR2_EL1 = 0xc01c, + AD_SYSREG_IFSR32_EL2 = 0xe281, + AD_SYSREG_ISR_EL1 = 0xc608, + AD_SYSREG_LORC_EL1 = 0xc523, + AD_SYSREG_LOREA_EL1 = 0xc521, + AD_SYSREG_LORID_EL1 = 0xc527, + AD_SYSREG_LORN_EL1 = 0xc522, + AD_SYSREG_LORSA_EL1 = 0xc520, + AD_SYSREG_MAIR_EL1 = 0xc510, + AD_SYSREG_MAIR_EL12 = 0xed10, + AD_SYSREG_MAIR_EL2 = 0xe510, + AD_SYSREG_MAIR_EL3 = 0xf510, + AD_SYSREG_MDCCINT_EL1 = 0x8010, + AD_SYSREG_MDCCSR_EL0 = 0x9808, + AD_SYSREG_MDCR_EL2 = 0xe089, + AD_SYSREG_MDCR_EL3 = 0xf099, + AD_SYSREG_MDRAR_EL1 = 0x8080, + AD_SYSREG_MDSCR_EL1 = 0x8012, + AD_SYSREG_MIDR_EL1 = 0xc000, + AD_SYSREG_MPIDR_EL1 = 0xc005, + AD_SYSREG_MVFR0_EL1 = 0xc018, + AD_SYSREG_MVFR1_EL1 = 0xc019, + AD_SYSREG_MVFR2_EL1 = 0xc01a, + AD_SYSREG_NZCV = 0xda10, + AD_SYSREG_OSDLR_EL1 = 0x809c, + AD_SYSREG_OSDTRRX_EL1 = 0x8002, + AD_SYSREG_OSDTRTX_EL1 = 0x801a, + AD_SYSREG_OSECCR_EL1 = 0x8032, + AD_SYSREG_OSLAR_EL1 = 0x8084, + AD_SYSREG_OSLSR_EL1 = 0x808c, + AD_SYSREG_PAN = 0xc213, + AD_SYSREG_PAR_EL1 = 0xc3a0, + AD_SYSREG_PMBIDR_EL1 = 0xc4d7, + AD_SYSREG_PMBLIMITR_EL1 = 0xc4d0, + AD_SYSREG_PMBPTR_EL1 = 0xc4d1, + AD_SYSREG_PMBSR_EL1 = 0xc4d3, + AD_SYSREG_PMCCFILTR_EL0 = 0xdf7f, + AD_SYSREG_PMCCNTR_EL0 = 0xdce8, + AD_SYSREG_PMCEID0_EL0 = 0xdce6, + AD_SYSREG_PMCEID1_EL0 = 0xdce7, + AD_SYSREG_PMCNTENCLR_EL0 = 0xdce2, + AD_SYSREG_PMCNTENSET_EL0 = 0xdce1, + AD_SYSREG_PMCR_EL0 = 0xdce0, + AD_SYSREG_PMINTENCLR_EL1 = 0xc4f2, + AD_SYSREG_PMINTENSET_EL1 = 0xc4f1, + AD_SYSREG_PMMIR_EL1 = 0xc4f6, + AD_SYSREG_PMOVSCLR_EL0 = 0xdce3, + AD_SYSREG_PMOVSSET_EL0 = 0xdcf3, + AD_SYSREG_PMSCR_EL1 = 0xc4c8, + AD_SYSREG_PMSCR_EL12 = 0xecc8, + AD_SYSREG_PMSCR_EL2 = 0xe4c8, + AD_SYSREG_PMSELR_EL0 = 0xdce5, + AD_SYSREG_PMSEVFR_EL1 = 0xc4cd, + AD_SYSREG_PMSFCR_EL1 = 0xc4cc, + AD_SYSREG_PMSICR_EL1 = 0xc4ca, + AD_SYSREG_PMSIDR_EL1 = 0xc4cf, + AD_SYSREG_PMSIRR_EL1 = 0xc4cb, + AD_SYSREG_PMSLATFR_EL1 = 0xc4ce, + AD_SYSREG_PMSWINC_EL0 = 0xdce4, + AD_SYSREG_PMUSERENR_EL0 = 0xdcf0, + AD_SYSREG_PMXEVCNTR_EL0 = 0xdcea, + AD_SYSREG_PMXEVTYPER_EL0 = 0xdce9, + AD_SYSREG_REVIDR_EL1 = 0xc006, + AD_SYSREG_RGSR_EL1 = 0xc085, + AD_SYSREG_RMR_EL1 = 0xc602, + AD_SYSREG_RMR_EL2 = 0xe602, + AD_SYSREG_RMR_EL3 = 0xf602, + AD_SYSREG_RNDR = 0xd920, + AD_SYSREG_RNDRRS = 0xd921, + AD_SYSREG_RVBAR_EL1 = 0xc601, + AD_SYSREG_RVBAR_EL2 = 0xe601, + AD_SYSREG_RVBAR_EL3 = 0xf601, + AD_SYSREG_SCR_EL3 = 0xf088, + AD_SYSREG_SCTLR_EL1 = 0xc080, + AD_SYSREG_SCTLR_EL12 = 0xe880, + AD_SYSREG_SCTLR_EL2 = 0xe080, + AD_SYSREG_SCTLR_EL3 = 0xf080, + AD_SYSREG_SCXTNUM_EL0 = 0xde87, + AD_SYSREG_SCXTNUM_EL1 = 0xc687, + AD_SYSREG_SCXTNUM_EL12 = 0xee87, + AD_SYSREG_SCXTNUM_EL2 = 0xe687, + AD_SYSREG_SCXTNUM_EL3 = 0xf687, + AD_SYSREG_SDER32_EL2 = 0xe099, + AD_SYSREG_SDER32_EL3 = 0xf089, + AD_SYSREG_SPSR_EL1 = 0xc200, + AD_SYSREG_SPSR_EL12 = 0xea00, + AD_SYSREG_SPSR_EL2 = 0xe200, + AD_SYSREG_SPSR_EL3 = 0xf200, + AD_SYSREG_SPSR_abt = 0xe219, + AD_SYSREG_SPSR_fiq = 0xe21b, + AD_SYSREG_SPSR_irq = 0xe218, + AD_SYSREG_SPSR_und = 0xe21a, + AD_SYSREG_SPSel = 0xc210, + AD_SYSREG_SP_EL0 = 0xc208, + AD_SYSREG_SP_EL1 = 0xe208, + AD_SYSREG_SP_EL2 = 0xf208, + AD_SYSREG_SSBS = 0xda16, + AD_SYSREG_TCO = 0xda17, + AD_SYSREG_TCR_EL1 = 0xc102, + AD_SYSREG_TCR_EL12 = 0xe902, + AD_SYSREG_TCR_EL2 = 0xe102, + AD_SYSREG_TCR_EL3 = 0xf102, + AD_SYSREG_TFSRE0_EL1 = 0xc2b1, + AD_SYSREG_TFSR_EL1 = 0xc2b0, + AD_SYSREG_TFSR_EL12 = 0xeab0, + AD_SYSREG_TFSR_EL2 = 0xe2b0, + AD_SYSREG_TFSR_EL3 = 0xf2b0, + AD_SYSREG_TPIDRRO_EL0 = 0xde83, + AD_SYSREG_TPIDR_EL0 = 0xde82, + AD_SYSREG_TPIDR_EL1 = 0xc684, + AD_SYSREG_TPIDR_EL2 = 0xe682, + AD_SYSREG_TPIDR_EL3 = 0xf682, + AD_SYSREG_TRFCR_EL1 = 0xc091, + AD_SYSREG_TRFCR_EL12 = 0xe891, + AD_SYSREG_TRFCR_EL2 = 0xe091, + AD_SYSREG_TTBR0_EL1 = 0xc100, + AD_SYSREG_TTBR0_EL12 = 0xe900, + AD_SYSREG_TTBR0_EL2 = 0xe100, + AD_SYSREG_TTBR0_EL3 = 0xf100, + AD_SYSREG_TTBR1_EL1 = 0xc101, + AD_SYSREG_TTBR1_EL12 = 0xe901, + AD_SYSREG_TTBR1_EL2 = 0xe101, + AD_SYSREG_UAO = 0xc214, + AD_SYSREG_VBAR_EL1 = 0xc600, + AD_SYSREG_VBAR_EL12 = 0xee00, + AD_SYSREG_VBAR_EL2 = 0xe600, + AD_SYSREG_VBAR_EL3 = 0xf600, + AD_SYSREG_VDISR_EL2 = 0xe609, + AD_SYSREG_VMPIDR_EL2 = 0xe005, + AD_SYSREG_VNCR_EL2 = 0xe110, + AD_SYSREG_VPIDR_EL2 = 0xe000, + AD_SYSREG_VSESR_EL2 = 0xe293, + AD_SYSREG_VSTCR_EL2 = 0xe132, + AD_SYSREG_VSTTBR_EL2 = 0xe130, + AD_SYSREG_VTCR_EL2 = 0xe10a, + AD_SYSREG_VTTBR_EL2 = 0xe108, + AD_SYSREG_AMEVCNTR00_EL0 = 0xdea0, + AD_SYSREG_AMEVCNTR01_EL0 = 0xdea1, + AD_SYSREG_AMEVCNTR02_EL0 = 0xdea2, + AD_SYSREG_AMEVCNTR03_EL0 = 0xdea3, + AD_SYSREG_AMEVCNTR04_EL0 = 0xdea4, + AD_SYSREG_AMEVCNTR05_EL0 = 0xdea5, + AD_SYSREG_AMEVCNTR06_EL0 = 0xdea6, + AD_SYSREG_AMEVCNTR07_EL0 = 0xdea7, + AD_SYSREG_AMEVCNTR08_EL0 = 0xdea8, + AD_SYSREG_AMEVCNTR09_EL0 = 0xdea9, + AD_SYSREG_AMEVCNTR010_EL0 = 0xdeaa, + AD_SYSREG_AMEVCNTR011_EL0 = 0xdeab, + AD_SYSREG_AMEVCNTR012_EL0 = 0xdeac, + AD_SYSREG_AMEVCNTR013_EL0 = 0xdead, + AD_SYSREG_AMEVCNTR014_EL0 = 0xdeae, + AD_SYSREG_AMEVCNTR015_EL0 = 0xdeaf, + AD_SYSREG_AMEVCNTR10_EL0 = 0xdee0, + AD_SYSREG_AMEVCNTR11_EL0 = 0xdee1, + AD_SYSREG_AMEVCNTR12_EL0 = 0xdee2, + AD_SYSREG_AMEVCNTR13_EL0 = 0xdee3, + AD_SYSREG_AMEVCNTR14_EL0 = 0xdee4, + AD_SYSREG_AMEVCNTR15_EL0 = 0xdee5, + AD_SYSREG_AMEVCNTR16_EL0 = 0xdee6, + AD_SYSREG_AMEVCNTR17_EL0 = 0xdee7, + AD_SYSREG_AMEVCNTR18_EL0 = 0xdee8, + AD_SYSREG_AMEVCNTR19_EL0 = 0xdee9, + AD_SYSREG_AMEVCNTR110_EL0 = 0xdeea, + AD_SYSREG_AMEVCNTR111_EL0 = 0xdeeb, + AD_SYSREG_AMEVCNTR112_EL0 = 0xdeec, + AD_SYSREG_AMEVCNTR113_EL0 = 0xdeed, + AD_SYSREG_AMEVCNTR114_EL0 = 0xdeee, + AD_SYSREG_AMEVCNTR115_EL0 = 0xdeef, + AD_SYSREG_AMEVTYPER00_EL0 = 0xdeb0, + AD_SYSREG_AMEVTYPER01_EL0 = 0xdeb1, + AD_SYSREG_AMEVTYPER02_EL0 = 0xdeb2, + AD_SYSREG_AMEVTYPER03_EL0 = 0xdeb3, + AD_SYSREG_AMEVTYPER04_EL0 = 0xdeb4, + AD_SYSREG_AMEVTYPER05_EL0 = 0xdeb5, + AD_SYSREG_AMEVTYPER06_EL0 = 0xdeb6, + AD_SYSREG_AMEVTYPER07_EL0 = 0xdeb7, + AD_SYSREG_AMEVTYPER08_EL0 = 0xdeb8, + AD_SYSREG_AMEVTYPER09_EL0 = 0xdeb9, + AD_SYSREG_AMEVTYPER010_EL0 = 0xdeba, + AD_SYSREG_AMEVTYPER011_EL0 = 0xdebb, + AD_SYSREG_AMEVTYPER012_EL0 = 0xdebc, + AD_SYSREG_AMEVTYPER013_EL0 = 0xdebd, + AD_SYSREG_AMEVTYPER014_EL0 = 0xdebe, + AD_SYSREG_AMEVTYPER015_EL0 = 0xdebf, + AD_SYSREG_AMEVTYPER10_EL0 = 0xdef0, + AD_SYSREG_AMEVTYPER11_EL0 = 0xdef1, + AD_SYSREG_AMEVTYPER12_EL0 = 0xdef2, + AD_SYSREG_AMEVTYPER13_EL0 = 0xdef3, + AD_SYSREG_AMEVTYPER14_EL0 = 0xdef4, + AD_SYSREG_AMEVTYPER15_EL0 = 0xdef5, + AD_SYSREG_AMEVTYPER16_EL0 = 0xdef6, + AD_SYSREG_AMEVTYPER17_EL0 = 0xdef7, + AD_SYSREG_AMEVTYPER18_EL0 = 0xdef8, + AD_SYSREG_AMEVTYPER19_EL0 = 0xdef9, + AD_SYSREG_AMEVTYPER110_EL0 = 0xdefa, + AD_SYSREG_AMEVTYPER111_EL0 = 0xdefb, + AD_SYSREG_AMEVTYPER112_EL0 = 0xdefc, + AD_SYSREG_AMEVTYPER113_EL0 = 0xdefd, + AD_SYSREG_AMEVTYPER114_EL0 = 0xdefe, + AD_SYSREG_AMEVTYPER115_EL0 = 0xdeff, + AD_SYSREG_DBGBCR0_EL1 = 0x8005, + AD_SYSREG_DBGBCR1_EL1 = 0x800d, + AD_SYSREG_DBGBCR2_EL1 = 0x8015, + AD_SYSREG_DBGBCR3_EL1 = 0x801d, + AD_SYSREG_DBGBCR4_EL1 = 0x8025, + AD_SYSREG_DBGBCR5_EL1 = 0x802d, + AD_SYSREG_DBGBCR6_EL1 = 0x8035, + AD_SYSREG_DBGBCR7_EL1 = 0x803d, + AD_SYSREG_DBGBCR8_EL1 = 0x8045, + AD_SYSREG_DBGBCR9_EL1 = 0x804d, + AD_SYSREG_DBGBCR10_EL1 = 0x8055, + AD_SYSREG_DBGBCR11_EL1 = 0x805d, + AD_SYSREG_DBGBCR12_EL1 = 0x8065, + AD_SYSREG_DBGBCR13_EL1 = 0x806d, + AD_SYSREG_DBGBCR14_EL1 = 0x8075, + AD_SYSREG_DBGBCR15_EL1 = 0x807d, + AD_SYSREG_DBGBVR0_EL1 = 0x8004, + AD_SYSREG_DBGBVR1_EL1 = 0x800c, + AD_SYSREG_DBGBVR2_EL1 = 0x8014, + AD_SYSREG_DBGBVR3_EL1 = 0x801c, + AD_SYSREG_DBGBVR4_EL1 = 0x8024, + AD_SYSREG_DBGBVR5_EL1 = 0x802c, + AD_SYSREG_DBGBVR6_EL1 = 0x8034, + AD_SYSREG_DBGBVR7_EL1 = 0x803c, + AD_SYSREG_DBGBVR8_EL1 = 0x8044, + AD_SYSREG_DBGBVR9_EL1 = 0x804c, + AD_SYSREG_DBGBVR10_EL1 = 0x8054, + AD_SYSREG_DBGBVR11_EL1 = 0x805c, + AD_SYSREG_DBGBVR12_EL1 = 0x8064, + AD_SYSREG_DBGBVR13_EL1 = 0x806c, + AD_SYSREG_DBGBVR14_EL1 = 0x8074, + AD_SYSREG_DBGBVR15_EL1 = 0x807c, + AD_SYSREG_DBGWCR0_EL1 = 0x8007, + AD_SYSREG_DBGWCR1_EL1 = 0x800f, + AD_SYSREG_DBGWCR2_EL1 = 0x8017, + AD_SYSREG_DBGWCR3_EL1 = 0x801f, + AD_SYSREG_DBGWCR4_EL1 = 0x8027, + AD_SYSREG_DBGWCR5_EL1 = 0x802f, + AD_SYSREG_DBGWCR6_EL1 = 0x8037, + AD_SYSREG_DBGWCR7_EL1 = 0x803f, + AD_SYSREG_DBGWCR8_EL1 = 0x8047, + AD_SYSREG_DBGWCR9_EL1 = 0x804f, + AD_SYSREG_DBGWCR10_EL1 = 0x8057, + AD_SYSREG_DBGWCR11_EL1 = 0x805f, + AD_SYSREG_DBGWCR12_EL1 = 0x8067, + AD_SYSREG_DBGWCR13_EL1 = 0x806f, + AD_SYSREG_DBGWCR14_EL1 = 0x8077, + AD_SYSREG_DBGWCR15_EL1 = 0x807f, + AD_SYSREG_DBGWVR0_EL1 = 0x8006, + AD_SYSREG_DBGWVR1_EL1 = 0x800e, + AD_SYSREG_DBGWVR2_EL1 = 0x8016, + AD_SYSREG_DBGWVR3_EL1 = 0x801e, + AD_SYSREG_DBGWVR4_EL1 = 0x8026, + AD_SYSREG_DBGWVR5_EL1 = 0x802e, + AD_SYSREG_DBGWVR6_EL1 = 0x8036, + AD_SYSREG_DBGWVR7_EL1 = 0x803e, + AD_SYSREG_DBGWVR8_EL1 = 0x8046, + AD_SYSREG_DBGWVR9_EL1 = 0x804e, + AD_SYSREG_DBGWVR10_EL1 = 0x8056, + AD_SYSREG_DBGWVR11_EL1 = 0x805e, + AD_SYSREG_DBGWVR12_EL1 = 0x8066, + AD_SYSREG_DBGWVR13_EL1 = 0x806e, + AD_SYSREG_DBGWVR14_EL1 = 0x8076, + AD_SYSREG_DBGWVR15_EL1 = 0x807e, + AD_SYSREG_PMEVCNTR0_EL0 = 0xdf40, + AD_SYSREG_PMEVCNTR1_EL0 = 0xdf41, + AD_SYSREG_PMEVCNTR2_EL0 = 0xdf42, + AD_SYSREG_PMEVCNTR3_EL0 = 0xdf43, + AD_SYSREG_PMEVCNTR4_EL0 = 0xdf44, + AD_SYSREG_PMEVCNTR5_EL0 = 0xdf45, + AD_SYSREG_PMEVCNTR6_EL0 = 0xdf46, + AD_SYSREG_PMEVCNTR7_EL0 = 0xdf47, + AD_SYSREG_PMEVCNTR8_EL0 = 0xdf48, + AD_SYSREG_PMEVCNTR9_EL0 = 0xdf49, + AD_SYSREG_PMEVCNTR10_EL0 = 0xdf4a, + AD_SYSREG_PMEVCNTR11_EL0 = 0xdf4b, + AD_SYSREG_PMEVCNTR12_EL0 = 0xdf4c, + AD_SYSREG_PMEVCNTR13_EL0 = 0xdf4d, + AD_SYSREG_PMEVCNTR14_EL0 = 0xdf4e, + AD_SYSREG_PMEVCNTR15_EL0 = 0xdf4f, + AD_SYSREG_PMEVCNTR16_EL0 = 0xdf50, + AD_SYSREG_PMEVCNTR17_EL0 = 0xdf51, + AD_SYSREG_PMEVCNTR18_EL0 = 0xdf52, + AD_SYSREG_PMEVCNTR19_EL0 = 0xdf53, + AD_SYSREG_PMEVCNTR20_EL0 = 0xdf54, + AD_SYSREG_PMEVCNTR21_EL0 = 0xdf55, + AD_SYSREG_PMEVCNTR22_EL0 = 0xdf56, + AD_SYSREG_PMEVCNTR23_EL0 = 0xdf57, + AD_SYSREG_PMEVCNTR24_EL0 = 0xdf58, + AD_SYSREG_PMEVCNTR25_EL0 = 0xdf59, + AD_SYSREG_PMEVCNTR26_EL0 = 0xdf5a, + AD_SYSREG_PMEVCNTR27_EL0 = 0xdf5b, + AD_SYSREG_PMEVCNTR28_EL0 = 0xdf5c, + AD_SYSREG_PMEVCNTR29_EL0 = 0xdf5d, + AD_SYSREG_PMEVCNTR30_EL0 = 0xdf5e, + AD_SYSREG_PMEVCNTR31_EL0 = 0xdf5f, + AD_SYSREG_PMEVTYPER0_EL0 = 0xdf60, + AD_SYSREG_PMEVTYPER1_EL0 = 0xdf61, + AD_SYSREG_PMEVTYPER2_EL0 = 0xdf62, + AD_SYSREG_PMEVTYPER3_EL0 = 0xdf63, + AD_SYSREG_PMEVTYPER4_EL0 = 0xdf64, + AD_SYSREG_PMEVTYPER5_EL0 = 0xdf65, + AD_SYSREG_PMEVTYPER6_EL0 = 0xdf66, + AD_SYSREG_PMEVTYPER7_EL0 = 0xdf67, + AD_SYSREG_PMEVTYPER8_EL0 = 0xdf68, + AD_SYSREG_PMEVTYPER9_EL0 = 0xdf69, + AD_SYSREG_PMEVTYPER10_EL0 = 0xdf6a, + AD_SYSREG_PMEVTYPER11_EL0 = 0xdf6b, + AD_SYSREG_PMEVTYPER12_EL0 = 0xdf6c, + AD_SYSREG_PMEVTYPER13_EL0 = 0xdf6d, + AD_SYSREG_PMEVTYPER14_EL0 = 0xdf6e, + AD_SYSREG_PMEVTYPER15_EL0 = 0xdf6f, + AD_SYSREG_PMEVTYPER16_EL0 = 0xdf70, + AD_SYSREG_PMEVTYPER17_EL0 = 0xdf71, + AD_SYSREG_PMEVTYPER18_EL0 = 0xdf72, + AD_SYSREG_PMEVTYPER19_EL0 = 0xdf73, + AD_SYSREG_PMEVTYPER20_EL0 = 0xdf74, + AD_SYSREG_PMEVTYPER21_EL0 = 0xdf75, + AD_SYSREG_PMEVTYPER22_EL0 = 0xdf76, + AD_SYSREG_PMEVTYPER23_EL0 = 0xdf77, + AD_SYSREG_PMEVTYPER24_EL0 = 0xdf78, + AD_SYSREG_PMEVTYPER25_EL0 = 0xdf79, + AD_SYSREG_PMEVTYPER26_EL0 = 0xdf7a, + AD_SYSREG_PMEVTYPER27_EL0 = 0xdf7b, + AD_SYSREG_PMEVTYPER28_EL0 = 0xdf7c, + AD_SYSREG_PMEVTYPER29_EL0 = 0xdf7d, + AD_SYSREG_PMEVTYPER30_EL0 = 0xdf7e, + AD_SYSREG_PMEVTYPER31_EL0 = 0xdf7f, +}; + +#endif diff --git a/src/third_party/armadillo/source/armadillo.c b/src/third_party/armadillo/source/armadillo.c new file mode 100644 index 000000000..bdb08f9bb --- /dev/null +++ b/src/third_party/armadillo/source/armadillo.c @@ -0,0 +1,122 @@ +#include +#include +#include + +#include "adefs.h" +#include "bits.h" +#include "common.h" +#include "instruction.h" +#include "strext.h" + +#include "BranchExcSys.h" +#include "DataProcessingImmediate.h" +#include "DataProcessingFloatingPoint.h" +#include "DataProcessingRegister.h" +#include "LoadsAndStores.h" + +static S32 _ArmadilloDisassemble(struct instruction *i, + struct ad_insn **_out){ + struct ad_insn *out = *_out; + + U32 op0 = bits(i->opcode, 25, 28); + + if(op0 == 0){ + out->group = AD_G_Reserved; + + U32 op1 = bits(i->opcode, 16, 24); + + if(op1 != 0) + return 1; + + U32 imm16 = bits(i->opcode, 0, 15); + + ADD_FIELD(out, op0); + ADD_FIELD(out, op1); + ADD_FIELD(out, imm16); + + ADD_IMM_OPERAND(out, AD_IMM_UINT, *(U32 *)&imm16); + + concat(&DECODE_STR(out), "udf #%#x", imm16); + + SET_INSTR_ID(out, AD_INSTR_UDF); + + return 0; + } + else if(op0 > 0 && op0 <= 3){ + return 1; + } + else if((op0 >> 1) == 4){ + out->group = AD_G_DataProcessingImmediate; + return DataProcessingImmediateDisassemble(i, out); + } + else if((op0 >> 1) == 5){ + out->group = AD_G_BranchExcSys; + return BranchExcSysDisassemble(i, out); + } + else if((op0 & ~10) == 4){ + out->group = AD_G_LoadsAndStores; + return LoadsAndStoresDisassemble(i, out); + } + else if((op0 & ~8) == 5){ + out->group = AD_G_DataProcessingRegister; + return DataProcessingRegisterDisassemble(i, out); + } + else if((op0 & ~8) == 7){ + out->group = AD_G_DataProcessingFloatingPoint; + return DataProcessingFloatingPointDisassemble(i, out); + } + + return 0; +} + +S32 ArmadilloDisassemble(U32 opcode, U64 PC, + struct ad_insn **out){ + if(!out || (out && *out)) + return 1; + + *out = (struct ad_insn*)malloc(sizeof(struct ad_insn)); + + (*out)->decoded = NULL; + + (*out)->group = AD_NONE; + (*out)->instr_id = AD_NONE; + + (*out)->fields = NULL; + (*out)->num_fields = 0; + + (*out)->operands = NULL; + (*out)->num_operands = 0; + + (*out)->cc = AD_NONE; + + struct instruction *i = instruction_new(opcode, PC); + + S32 result = _ArmadilloDisassemble(i, out); + + if(result){ + free(DECODE_STR(*out)); + DECODE_STR(*out) = NULL; + concat(&DECODE_STR(*out), ".long %#x", i->opcode); + } + + free(i); + + return result; +} + +S32 ArmadilloDone(struct ad_insn **_insn){ + if(!_insn) + return 1; + + struct ad_insn *insn = *_insn; + + free(insn->decoded); + free(insn->fields); + free(insn->operands); + + free(insn); + + *_insn = NULL; + + return 0; +} diff --git a/src/third_party/armadillo/source/armadillo.h b/src/third_party/armadillo/source/armadillo.h new file mode 100644 index 000000000..151af778a --- /dev/null +++ b/src/third_party/armadillo/source/armadillo.h @@ -0,0 +1,9 @@ +#ifndef _ARMADILLO_H_ +#define _ARMADILLO_H_ + +#include "adefs.h" + +S32 ArmadilloDisassemble(U32 opcode, U64 PC, struct ad_insn **out); +S32 ArmadilloDone(struct ad_insn **insn); + +#endif diff --git a/src/third_party/armadillo/source/bits.c b/src/third_party/armadillo/source/bits.c new file mode 100644 index 000000000..37d9a78f4 --- /dev/null +++ b/src/third_party/armadillo/source/bits.c @@ -0,0 +1,15 @@ +#include "bits.h" + +U32 bits(U32 number, U32 start, U32 end){ + U32 amount = (end - start) + 1; + U32 mask = ((1 << amount) - 1) << start; + + return (number & mask) >> start; +} + +U32 sign_extend(U32 number, S32 numbits){ + if(number & (1 << (numbits - 1))) + return number | ~((1 << numbits) - 1); + + return number; +} diff --git a/src/third_party/armadillo/source/bits.h b/src/third_party/armadillo/source/bits.h new file mode 100644 index 000000000..88f483c02 --- /dev/null +++ b/src/third_party/armadillo/source/bits.h @@ -0,0 +1,7 @@ +#ifndef _BITS_H_ +#define _BITS_H_ + +U32 bits(U32, U32 start, U32 end); +U32 sign_extend(U32 number, S32 numbits); + +#endif diff --git a/src/third_party/armadillo/source/common.h b/src/third_party/armadillo/source/common.h new file mode 100644 index 000000000..c00765bbc --- /dev/null +++ b/src/third_party/armadillo/source/common.h @@ -0,0 +1,198 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +struct itab { + const char *instr_s; + S32 instr_id; +}; + +#define OOB(x, a) (((size_t)x) >= (sizeof(a) / sizeof(*a))) + +/* macros to enable cleaner "signed" hex in format strings */ +#define S_X "%s%#x" +#define S_LX "%s%#lx" + +#define S_A(x) ((S32)x) < 0 ? "-" : "", ((S32)x) < 0 ? -((S32)x) : ((S32)x) +#define S_LA(x) ((S64)x) < 0 ? "-" : "", ((S64)x) < 0 ? -((S64)x) : ((S64)x) + +#define _128_BIT (128) +#define _64_BIT (64) +#define _32_BIT (32) +#define _16_BIT (16) +#define _8_BIT (8) + +#define NO_PREFER_ZR (0) +#define PREFER_ZR (1) + +/* macros for magic numbers for clarity */ +#define _SZ(x) (x) +#define _ZR(x) (x) +#define _SYSREG(x) (x) +#define _RTBL(x) (x) + +#define ADD_FIELD(i, field) \ + do { \ + if(!i->fields) \ + i->fields = (S32*)malloc(sizeof(S32) * ++i->num_fields); \ + else{ \ + S32 *fields_rea = realloc(i->fields, \ + sizeof(S32) * ++i->num_fields); \ + i->fields = fields_rea; \ + } \ + i->fields[i->num_fields - 1] = field; \ + } while (0) + +#define ADD_REG_OPERAND(i, rn_, sz_, zr_, sysreg_, rtbl_) \ + do { \ + if(!i->operands) \ + i->operands = (struct ad_operand*)malloc(sizeof(struct ad_operand) * ++i->num_operands); \ + else{ \ + struct ad_operand *operands_rea = (struct ad_operand*)realloc(i->operands, \ + sizeof(struct ad_operand) * ++i->num_operands); \ + i->operands = operands_rea; \ + } \ + i->operands[i->num_operands - 1].type = AD_OP_REG; \ + i->operands[i->num_operands - 1].op_reg.rn = rn_; \ + i->operands[i->num_operands - 1].op_reg.sz = sz_; \ + if((rtbl_) != AD_RTBL_GEN_32 && (rtbl_) != AD_RTBL_GEN_64) \ + i->operands[i->num_operands - 1].op_reg.fp = 1; \ + else \ + i->operands[i->num_operands - 1].op_reg.fp = 0; \ + i->operands[i->num_operands - 1].op_reg.zr = zr_; \ + i->operands[i->num_operands - 1].op_reg.sysreg = sysreg_; \ + i->operands[i->num_operands - 1].op_reg.rtbl = rtbl_; \ + } while (0) + +#define ADD_SHIFT_OPERAND(i, type_, amt_) \ + do { \ + if(!i->operands) \ + i->operands = (struct ad_operand*)malloc(sizeof(struct ad_operand) * ++i->num_operands); \ + else{ \ + struct ad_operand *operands_rea = (struct ad_operand*)realloc(i->operands, \ + sizeof(struct ad_operand) * ++i->num_operands); \ + i->operands = operands_rea; \ + } \ + i->operands[i->num_operands - 1].type = AD_OP_SHIFT; \ + i->operands[i->num_operands - 1].op_shift.type = type_; \ + i->operands[i->num_operands - 1].op_shift.amt = amt_; \ + } while (0) + +#define ADD_IMM_OPERAND(i, type_, bits_) \ + do { \ + if(!i->operands) \ + i->operands = (struct ad_operand*)malloc(sizeof(struct ad_operand) * ++i->num_operands); \ + else{ \ + struct ad_operand *operands_rea = (struct ad_operand*)realloc(i->operands, \ + sizeof(struct ad_operand) * ++i->num_operands); \ + i->operands = operands_rea; \ + } \ + i->operands[i->num_operands - 1].type = AD_OP_IMM; \ + i->operands[i->num_operands - 1].op_imm.type = type_; \ + i->operands[i->num_operands - 1].op_imm.bits = bits_; \ + } while (0) + +#define DECODE_STR(x) ((x)->decoded) + +#define SET_INSTR_ID(i, id_) \ + do { \ + i->instr_id = id_; \ + } while (0) + +#define SET_CC(i, cc_) \ + do { \ + i->cc = cc_; \ + } while (0) + +static inline const char *GET_GEN_REG(const char **rtbl, U32 idx, + S32 prefer_zr){ + if(idx > 31) + return "(reg idx oob)"; + + if(idx == 31 && prefer_zr) + idx++; + + return rtbl[idx]; +} + +static inline const char *GET_FP_REG(const char **rtbl, U32 idx){ + if(idx > 31) + return "(reg idx oob)"; + + return rtbl[idx]; +} + +static const char *AD_RTBL_GEN_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", "wzr" +}; + +static const char *AD_RTBL_GEN_64[] = { + "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", "xzr" +}; + +static const char *AD_RTBL_FP_8[] = { + "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" +}; + +static const char *AD_RTBL_FP_16[] = { + "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" +}; + +static const char *AD_RTBL_FP_32[] = { + "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" +}; + +static const char *AD_RTBL_FP_64[] = { + "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" +}; + +static const char *AD_RTBL_FP_128[] = { + "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" +}; + +static const char *AD_RTBL_FP_V_128[] = { + "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" +}; + +static U64 AD_RTBL_GEN_32_SZ = sizeof(AD_RTBL_GEN_32) / sizeof(*AD_RTBL_GEN_32); +static U64 AD_RTBL_GEN_64_SZ = sizeof(AD_RTBL_GEN_64) / sizeof(*AD_RTBL_GEN_64); + +static U64 AD_RTBL_FP_8_SZ = sizeof(AD_RTBL_FP_8) / sizeof(*AD_RTBL_FP_8); +static U64 AD_RTBL_FP_16_SZ = sizeof(AD_RTBL_FP_16) / sizeof(*AD_RTBL_FP_16); +static U64 AD_RTBL_FP_32_SZ = sizeof(AD_RTBL_FP_32) / sizeof(*AD_RTBL_FP_32); +static U64 AD_RTBL_FP_64_SZ = sizeof(AD_RTBL_FP_64) / sizeof(*AD_RTBL_FP_64); +static U64 AD_RTBL_FP_128_SZ = sizeof(AD_RTBL_FP_128) / sizeof(*AD_RTBL_FP_128); +static U64 AD_RTBL_FP_V_128_SZ = sizeof(AD_RTBL_FP_V_128) / sizeof(*AD_RTBL_FP_V_128); + +#endif diff --git a/src/third_party/armadillo/source/instruction.c b/src/third_party/armadillo/source/instruction.c new file mode 100644 index 000000000..b6d3cc3d7 --- /dev/null +++ b/src/third_party/armadillo/source/instruction.c @@ -0,0 +1,16 @@ +#include + +#include "instruction.h" + +struct instruction *instruction_new(U32 opcode, U64 PC){ + struct instruction *i = (struct instruction *)malloc(sizeof(struct instruction)); + + i->opcode = opcode; + i->PC = PC; + + return i; +} + +void instruction_free(struct instruction *i){ + free(i); +} diff --git a/src/third_party/armadillo/source/instruction.h b/src/third_party/armadillo/source/instruction.h new file mode 100644 index 000000000..f91644a75 --- /dev/null +++ b/src/third_party/armadillo/source/instruction.h @@ -0,0 +1,12 @@ +#ifndef _INSTRUCTION_H_ +#define _INSTRUCTION_H_ + +struct instruction { + U32 opcode; + U64 PC; +}; + +struct instruction *instruction_new(U32, U64); +void instruction_free(struct instruction *); + +#endif diff --git a/src/third_party/armadillo/source/strext.c b/src/third_party/armadillo/source/strext.c new file mode 100644 index 000000000..d9e9d8b54 --- /dev/null +++ b/src/third_party/armadillo/source/strext.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +static S32 _concat_internal(char **dst, const char *src, va_list args){ + if(!src || !dst) + return 0; + + U64 srclen = strlen(src), dstlen = 0; + + if(*dst) + dstlen = strlen(*dst); + + /* Back up args before it gets used. Client calls va_end + * on the parameter themselves when calling vconcat. + */ + va_list args1; + va_copy(args1, args); + + U64 total = srclen + dstlen + vsnprintf(NULL, 0, src, args) + 1; + + char *dst1 = malloc(total); + + if(!(*dst)) + *dst1 = '\0'; + else{ + strncpy(dst1, *dst, dstlen + 1); + free(*dst); + *dst = NULL; + } + + S32 w = vsnprintf(dst1 + dstlen, total, src, args1); + + va_end(args1); + + *dst = (char*)realloc(dst1, strlen(dst1) + 1); + + return w; +} + +S32 concat(char **dst, const char *src, ...){ + va_list args; + va_start(args, src); + + S32 w = _concat_internal(dst, src, args); + + va_end(args); + + return w; +} + +S32 vconcat(char **dst, const char *src, va_list args){ + return _concat_internal(dst, src, args); +} diff --git a/src/third_party/armadillo/source/strext.h b/src/third_party/armadillo/source/strext.h new file mode 100644 index 000000000..4f30c2062 --- /dev/null +++ b/src/third_party/armadillo/source/strext.h @@ -0,0 +1,9 @@ +#ifndef _STREXT_H_ +#define _STREXT_H_ + +#include + +S32 vconcat(char **, const char *, va_list); +S32 concat(char **, const char *, ...); + +#endif diff --git a/src/third_party/armadillo/source/utils.c b/src/third_party/armadillo/source/utils.c new file mode 100644 index 000000000..54f2a5f76 --- /dev/null +++ b/src/third_party/armadillo/source/utils.c @@ -0,0 +1,202 @@ +#include +#include +#include + +#include "utils.h" + +/* Thanks https://github.com/xerub/macho/blob/master/patchfinder64.c */ +static U64 RORZeroExtendOnes(U32 M, U32 N, + U32 R){ + U64 val = Ones(M, N); + + if(R == 0) + return val; + + return ((val >> R) & (((U64)1 << (N - R)) - 1)) | + ((val & (((U64)1 << R) - 1)) << (N - R)); +} + +S32 HighestSetBit(U32 number, U32 n){ + S32 ret = -1; + + for(S32 i = n-1; i>=0; i--){ + if(number & (1 << i)) + return i; + } + + return ret; +} + +S32 LowestSetBit(U32 number, U32 n){ + S32 ret = n; + + for(S32 i=0; i> i) & 1) == 1) + result++; + } + + return result; +} + +U64 Ones(S32 len, S32 N){ + (void)N; + U64 ret = 0; + + for(S32 i=len-1; i>=0; i--) + ret |= ((U64)1 << i); + + return ret; +} + +S32 DecodeBitMasks(U32 N, U32 imms, U32 immr, + S32 immediate, U64 *out){ + U32 num = (N << 6) | (~imms & 0x3f); + U32 len = HighestSetBit(num, 7); + + if(len < 1) + return -1; + + U32 levels = Ones(len, 0); + + if(immediate && ((imms & levels) == levels)) + return -1; + + U32 S = imms & levels; + U32 R = immr & levels; + U32 esize = 1 << len; + + *out = replicate(RORZeroExtendOnes(S + 1, esize, R), sizeof(U64) * CHAR_BIT, esize); + + return 0; +} + +/* + * num: the number to replicate + * nbits: how many bits make up this number + * cnt: how many times to replicate + */ +U64 replicate(U64 num, S32 nbits, S32 cnt){ + U64 result = 0; + + for(S32 i=0; i> 6) != 1) + return 0; + + if(sf == 0 && (combined >> 5) != 0) + return 0; + + if(imms < 16) + return (-immr % 16) <= (15 - imms); + + if(imms >= (width - 15)) + return (immr % 16) <= (imms - (width - 15)); + + return 0; +} + +S32 IsZero(U64 x){ + return x == 0; +} + +S32 IsOnes(U64 x, S32 n){ + return x == Ones(n, 0); +} + +S32 BFXPreferred(U32 sf, U32 uns, + U32 imms, U32 immr){ + if(imms < immr) + return 0; + + if(imms == ((sf << 6) | 0x3f)) + return 0; + + if(immr == 0){ + if(sf == 0 && (imms == 0x7 || imms == 0xf)) + return 0; + else if(((sf << 1) | uns) == 0x2 && (imms == 0x7 || imms == 0xf || imms == 0x1f)) + return 0; + } + + return 1; +} + +char *decode_reg_extend(U32 op){ + switch(op){ + case 0x0: + return "uxtb"; + case 0x1: + return "uxth"; + case 0x2: + return "uxtw"; + case 0x3: + return "uxtx"; + case 0x4: + return "sxtb"; + case 0x5: + return "sxth"; + case 0x6: + return "sxtw"; + case 0x7: + return "sxtx"; + default: + return NULL; + }; +} + +const char *decode_cond(U32 cond){ + switch(cond){ + case 0: return "eq"; + case 1: return "ne"; + case 2: return "cs"; + case 3: return "cc"; + case 4: return "mi"; + case 5: return "pl"; + case 6: return "vs"; + case 7: return "vc"; + case 8: return "hi"; + case 9: return "ls"; + case 10: return "ge"; + case 11: return "lt"; + case 12: return "gt"; + case 13: return "le"; + case 14: return "al"; + case 15: return "nv"; + default: return NULL; + }; +} + +const char *get_arrangement(U32 size, U32 Q){ + if(size == 0) + return Q == 0 ? "8b" : "16b"; + if(size == 1) + return Q == 0 ? "4h" : "8h"; + if(size == 2) + return Q == 0 ? "2s" : "4s"; + if(size == 3) + return Q == 0 ? "1d" : "2d"; + + return NULL; +} diff --git a/src/third_party/armadillo/source/utils.h b/src/third_party/armadillo/source/utils.h new file mode 100644 index 000000000..c031d669e --- /dev/null +++ b/src/third_party/armadillo/source/utils.h @@ -0,0 +1,18 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +S32 HighestSetBit(U32, U32); +S32 LowestSetBit(U32 number, U32 n); +S32 BitCount(U32, U32); +U64 Ones(S32 len, S32 N); +S32 DecodeBitMasks(U32 N, U32 imms, U32 immr, S32 immediate, U64 *out); +U64 replicate(U64, S32, S32); +S32 MoveWidePreferred(U32 sf, U32 immN, U32 immr, U32 imms); +S32 IsZero(U64 x); +S32 IsOnes(U64 x, S32 n); +S32 BFXPreferred(U32 sf, U32 uns, U32 imms, U32 immr); +char *decode_reg_extend(U32 op); +const char *decode_cond(U32 cond); +const char *get_arrangement(U32 size, U32 Q); + +#endif