diff options
Diffstat (limited to 'gdb/arch/aarch64-insn.h')
-rw-r--r-- | gdb/arch/aarch64-insn.h | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/gdb/arch/aarch64-insn.h b/gdb/arch/aarch64-insn.h index 47f6715..01a5d73 100644 --- a/gdb/arch/aarch64-insn.h +++ b/gdb/arch/aarch64-insn.h @@ -21,6 +21,129 @@ extern int aarch64_debug; +/* List of opcodes that we need for building the jump pad and relocating + an instruction. */ + +enum aarch64_opcodes +{ + /* B 0001 01ii iiii iiii iiii iiii iiii iiii */ + /* BL 1001 01ii iiii iiii iiii iiii iiii iiii */ + /* B.COND 0101 0100 iiii iiii iiii iiii iii0 cccc */ + /* CBZ s011 0100 iiii iiii iiii iiii iiir rrrr */ + /* CBNZ s011 0101 iiii iiii iiii iiii iiir rrrr */ + /* TBZ b011 0110 bbbb biii iiii iiii iiir rrrr */ + /* TBNZ b011 0111 bbbb biii iiii iiii iiir rrrr */ + B = 0x14000000, + BL = 0x80000000 | B, + BCOND = 0x40000000 | B, + CBZ = 0x20000000 | B, + CBNZ = 0x21000000 | B, + TBZ = 0x36000000 | B, + TBNZ = 0x37000000 | B, + /* BLR 1101 0110 0011 1111 0000 00rr rrr0 0000 */ + BLR = 0xd63f0000, + /* RET 1101 0110 0101 1111 0000 00rr rrr0 0000 */ + RET = 0xd65f0000, + /* STP s010 100o o0ii iiii irrr rrrr rrrr rrrr */ + /* LDP s010 100o o1ii iiii irrr rrrr rrrr rrrr */ + /* STP (SIMD&VFP) ss10 110o o0ii iiii irrr rrrr rrrr rrrr */ + /* LDP (SIMD&VFP) ss10 110o o1ii iiii irrr rrrr rrrr rrrr */ + STP = 0x28000000, + LDP = 0x28400000, + STP_SIMD_VFP = 0x04000000 | STP, + LDP_SIMD_VFP = 0x04000000 | LDP, + /* STR ss11 100o 00xi iiii iiii xxrr rrrr rrrr */ + /* LDR ss11 100o 01xi iiii iiii xxrr rrrr rrrr */ + /* LDRSW 1011 100o 10xi iiii iiii xxrr rrrr rrrr */ + STR = 0x38000000, + LDR = 0x00400000 | STR, + LDRSW = 0x80800000 | STR, + /* LDAXR ss00 1000 0101 1111 1111 11rr rrrr rrrr */ + LDAXR = 0x085ffc00, + /* STXR ss00 1000 000r rrrr 0111 11rr rrrr rrrr */ + STXR = 0x08007c00, + /* STLR ss00 1000 1001 1111 1111 11rr rrrr rrrr */ + STLR = 0x089ffc00, + /* MOV s101 0010 1xxi iiii iiii iiii iiir rrrr */ + /* MOVK s111 0010 1xxi iiii iiii iiii iiir rrrr */ + MOV = 0x52800000, + MOVK = 0x20000000 | MOV, + /* ADD s00o ooo1 xxxx xxxx xxxx xxxx xxxx xxxx */ + /* SUB s10o ooo1 xxxx xxxx xxxx xxxx xxxx xxxx */ + /* SUBS s11o ooo1 xxxx xxxx xxxx xxxx xxxx xxxx */ + ADD = 0x01000000, + SUB = 0x40000000 | ADD, + SUBS = 0x20000000 | SUB, + /* AND s000 1010 xx0x xxxx xxxx xxxx xxxx xxxx */ + /* ORR s010 1010 xx0x xxxx xxxx xxxx xxxx xxxx */ + /* ORN s010 1010 xx1x xxxx xxxx xxxx xxxx xxxx */ + /* EOR s100 1010 xx0x xxxx xxxx xxxx xxxx xxxx */ + AND = 0x0a000000, + ORR = 0x20000000 | AND, + ORN = 0x00200000 | ORR, + EOR = 0x40000000 | AND, + /* LSLV s001 1010 110r rrrr 0010 00rr rrrr rrrr */ + /* LSRV s001 1010 110r rrrr 0010 01rr rrrr rrrr */ + /* ASRV s001 1010 110r rrrr 0010 10rr rrrr rrrr */ + LSLV = 0x1ac02000, + LSRV = 0x00000400 | LSLV, + ASRV = 0x00000800 | LSLV, + /* SBFM s001 0011 0nii iiii iiii iirr rrrr rrrr */ + SBFM = 0x13000000, + /* UBFM s101 0011 0nii iiii iiii iirr rrrr rrrr */ + UBFM = 0x40000000 | SBFM, + /* CSINC s001 1010 100r rrrr cccc 01rr rrrr rrrr */ + CSINC = 0x9a800400, + /* MUL s001 1011 000r rrrr 0111 11rr rrrr rrrr */ + MUL = 0x1b007c00, + /* MSR (register) 1101 0101 0001 oooo oooo oooo ooor rrrr */ + /* MRS 1101 0101 0011 oooo oooo oooo ooor rrrr */ + MSR = 0xd5100000, + MRS = 0x00200000 | MSR, + /* HINT 1101 0101 0000 0011 0010 oooo ooo1 1111 */ + HINT = 0xd503201f, + SEVL = (5 << 5) | HINT, + WFE = (2 << 5) | HINT, + NOP = (0 << 5) | HINT, +}; + +/* Representation of a general purpose register of the form xN or wN. + + This type is used by emitting functions that take registers as operands. */ + +struct aarch64_register +{ + unsigned num; + int is64; +}; + +/* Representation of a memory operand, used for load and store + instructions. + + The types correspond to the following variants: + + MEMORY_OPERAND_OFFSET: LDR rt, [rn, #offset] + MEMORY_OPERAND_PREINDEX: LDR rt, [rn, #index]! + MEMORY_OPERAND_POSTINDEX: LDR rt, [rn], #index */ + +struct aarch64_memory_operand +{ + /* Type of the operand. */ + enum + { + MEMORY_OPERAND_OFFSET, + MEMORY_OPERAND_PREINDEX, + MEMORY_OPERAND_POSTINDEX, + } type; + /* Index from the base register. */ + int32_t index; +}; + +/* Helper macro to mask and shift a value into a bitfield. */ + +#define ENCODE(val, size, offset) \ + ((uint32_t) ((val & ((1ULL << size) - 1)) << offset)) + int aarch64_decode_adr (CORE_ADDR addr, uint32_t insn, int *is_adrp, unsigned *rd, int32_t *offset); @@ -86,4 +209,113 @@ void aarch64_relocate_instruction (uint32_t insn, const struct aarch64_insn_visitor *visitor, struct aarch64_insn_data *data); +#define can_encode_int32(val, bits) \ + (((val) >> (bits)) == 0 || ((val) >> (bits)) == -1) + +/* Write a B or BL instruction into *BUF. + + B #offset + BL #offset + + IS_BL specifies if the link register should be updated. + OFFSET is the immediate offset from the current PC. It is + byte-addressed but should be 4 bytes aligned. It has a limited range of + +/- 128MB (26 bits << 2). */ + +#define emit_b(buf, is_bl, offset) \ + emit_insn (buf, ((is_bl) ? BL : B) | (ENCODE ((offset) >> 2, 26, 0))) + +/* Write a BCOND instruction into *BUF. + + B.COND #offset + + COND specifies the condition field. + OFFSET is the immediate offset from the current PC. It is + byte-addressed but should be 4 bytes aligned. It has a limited range of + +/- 1MB (19 bits << 2). */ + +#define emit_bcond(buf, cond, offset) \ + emit_insn (buf, \ + BCOND | ENCODE ((offset) >> 2, 19, 5) \ + | ENCODE ((cond), 4, 0)) + +/* Write a CBZ or CBNZ instruction into *BUF. + + CBZ rt, #offset + CBNZ rt, #offset + + IS_CBNZ distinguishes between CBZ and CBNZ instructions. + RN is the register to test. + OFFSET is the immediate offset from the current PC. It is + byte-addressed but should be 4 bytes aligned. It has a limited range of + +/- 1MB (19 bits << 2). */ + +#define emit_cb(buf, is_cbnz, rt, offset) \ + emit_insn (buf, \ + ((is_cbnz) ? CBNZ : CBZ) \ + | ENCODE (rt.is64, 1, 31) /* sf */ \ + | ENCODE (offset >> 2, 19, 5) /* imm19 */ \ + | ENCODE (rt.num, 5, 0)) + +/* Write a LDR instruction into *BUF. + + LDR rt, [rn, #offset] + LDR rt, [rn, #index]! + LDR rt, [rn], #index + + RT is the register to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to + 0 .. 32760 range (12 bits << 3). */ + +#define emit_ldr(buf, rt, rn, operand) \ + emit_load_store (buf, rt.is64 ? 3 : 2, LDR, rt, rn, operand) + +/* Write a LDRSW instruction into *BUF. The register size is 64-bit. + + LDRSW xt, [rn, #offset] + LDRSW xt, [rn, #index]! + LDRSW xt, [rn], #index + + RT is the register to store. + RN is the base address register. + OFFSET is the immediate to add to the base address. It is limited to + 0 .. 16380 range (12 bits << 2). */ + +#define emit_ldrsw(buf, rt, rn, operand) \ + emit_load_store (buf, 3, LDRSW, rt, rn, operand) + + +/* Write a TBZ or TBNZ instruction into *BUF. + + TBZ rt, #bit, #offset + TBNZ rt, #bit, #offset + + IS_TBNZ distinguishes between TBZ and TBNZ instructions. + RT is the register to test. + BIT is the index of the bit to test in register RT. + OFFSET is the immediate offset from the current PC. It is + byte-addressed but should be 4 bytes aligned. It has a limited range of + +/- 32KB (14 bits << 2). */ + +#define emit_tb(buf, is_tbnz, bit, rt, offset) \ + emit_insn (buf, \ + ((is_tbnz) ? TBNZ: TBZ) \ + | ENCODE (bit >> 5, 1, 31) /* b5 */ \ + | ENCODE (bit, 5, 19) /* b40 */ \ + | ENCODE (offset >> 2, 14, 5) /* imm14 */ \ + | ENCODE (rt.num, 5, 0)) + +/* Write a NOP instruction into *BUF. */ + +#define emit_nop(buf) emit_insn (buf, NOP) + +int emit_insn (uint32_t *buf, uint32_t insn); + +int emit_load_store (uint32_t *buf, uint32_t size, + enum aarch64_opcodes opcode, + struct aarch64_register rt, + struct aarch64_register rn, + struct aarch64_memory_operand operand); + #endif |