diff options
Diffstat (limited to 'gdb/gdbserver/linux-aarch64-low.c')
-rw-r--r-- | gdb/gdbserver/linux-aarch64-low.c | 323 |
1 files changed, 3 insertions, 320 deletions
diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c index 1241434..9450449 100644 --- a/gdb/gdbserver/linux-aarch64-low.c +++ b/gdb/gdbserver/linux-aarch64-low.c @@ -584,92 +584,6 @@ aarch64_get_thread_area (int lwpid, CORE_ADDR *addrp) return 0; } -/* 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, -}; - /* List of condition codes that we need. */ enum aarch64_condition_codes @@ -683,16 +597,6 @@ enum aarch64_condition_codes LE = 0xd, }; -/* 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 an operand. At this time, it only supports register and immediate types. */ @@ -779,28 +683,6 @@ immediate_operand (uint32_t imm) return operand; } -/* 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 function to create an offset memory operand. For example: @@ -852,108 +734,6 @@ enum aarch64_system_control_registers TPIDR_EL0 = (0x1 << 14) | (0x3 << 11) | (0xd << 7) | (0x0 << 3) | 0x2 }; -/* Helper macro to mask and shift a value into a bitfield. */ - -#define ENCODE(val, size, offset) \ - ((uint32_t) ((val & ((1ULL << size) - 1)) << offset)) - -/* Write a 32-bit unsigned integer INSN info *BUF. Return the number of - instructions written (aka. 1). */ - -static int -emit_insn (uint32_t *buf, uint32_t insn) -{ - *buf = insn; - return 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). */ - -static int -emit_b (uint32_t *buf, int is_bl, int32_t offset) -{ - uint32_t imm26 = ENCODE (offset >> 2, 26, 0); - - if (is_bl) - return emit_insn (buf, BL | imm26); - else - return emit_insn (buf, B | imm26); -} - -/* 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). */ - -static int -emit_bcond (uint32_t *buf, unsigned cond, int32_t offset) -{ - return 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). */ - -static int -emit_cb (uint32_t *buf, int is_cbnz, struct aarch64_register rt, - int32_t offset) -{ - uint32_t imm19 = ENCODE (offset >> 2, 19, 5); - uint32_t sf = ENCODE (rt.is64, 1, 31); - - if (is_cbnz) - return emit_insn (buf, CBNZ | sf | imm19 | ENCODE (rt.num, 5, 0)); - else - return emit_insn (buf, CBZ | sf | imm19 | ENCODE (rt.num, 5, 0)); -} - -/* 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). */ - -static int -emit_tb (uint32_t *buf, int is_tbnz, unsigned bit, - struct aarch64_register rt, int32_t offset) -{ - uint32_t imm14 = ENCODE (offset >> 2, 14, 5); - uint32_t b40 = ENCODE (bit, 5, 19); - uint32_t b5 = ENCODE (bit >> 5, 1, 31); - - if (is_tbnz) - return emit_insn (buf, TBNZ | b5 | b40 | imm14 | ENCODE (rt.num, 5, 0)); - else - return emit_insn (buf, TBZ | b5 | b40 | imm14 | ENCODE (rt.num, 5, 0)); -} - /* Write a BLR instruction into *BUF. BLR rn @@ -1100,70 +880,9 @@ emit_stp_q_offset (uint32_t *buf, unsigned rt, unsigned rt2, uint32_t pre_index = ENCODE (1, 1, 24); return emit_insn (buf, STP_SIMD_VFP | opc | pre_index - | ENCODE (offset >> 4, 7, 15) | ENCODE (rt2, 5, 10) - | ENCODE (rn.num, 5, 5) | ENCODE (rt, 5, 0)); -} - -/* Helper function emitting a load or store instruction. */ - -static 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) -{ - uint32_t op; - - switch (operand.type) - { - case MEMORY_OPERAND_OFFSET: - { - op = ENCODE (1, 1, 24); - - return emit_insn (buf, opcode | ENCODE (size, 2, 30) | op - | ENCODE (operand.index >> 3, 12, 10) - | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); - } - case MEMORY_OPERAND_POSTINDEX: - { - uint32_t post_index = ENCODE (1, 2, 10); - - op = ENCODE (0, 1, 24); - - return emit_insn (buf, opcode | ENCODE (size, 2, 30) | op - | post_index | ENCODE (operand.index, 9, 12) - | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); - } - case MEMORY_OPERAND_PREINDEX: - { - uint32_t pre_index = ENCODE (3, 2, 10); - - op = ENCODE (0, 1, 24); - - return emit_insn (buf, opcode | ENCODE (size, 2, 30) | op - | pre_index | ENCODE (operand.index, 9, 12) - | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); - } - default: - return 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). */ - -static int -emit_ldr (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rn, struct aarch64_memory_operand operand) -{ - return emit_load_store (buf, rt.is64 ? 3 : 2, LDR, rt, rn, operand); + | ENCODE (offset >> 4, 7, 15) + | ENCODE (rt2, 5, 10) + | ENCODE (rn.num, 5, 5) | ENCODE (rt, 5, 0)); } /* Write a LDRH instruction into *BUF. @@ -1204,24 +923,7 @@ emit_ldrb (uint32_t *buf, struct aarch64_register rt, return emit_load_store (buf, 0, 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). */ - -static int -emit_ldrsw (uint32_t *buf, struct aarch64_register rt, - struct aarch64_register rn, - struct aarch64_memory_operand operand) -{ - return emit_load_store (buf, 3, LDRSW, rt, rn, operand); -} /* Write a STR instruction into *BUF. @@ -1816,14 +1518,6 @@ emit_cset (uint32_t *buf, struct aarch64_register rd, unsigned cond) return emit_csinc (buf, rd, xzr, xzr, cond ^ 0x1); } -/* Write a NOP instruction into *BUF. */ - -static int -emit_nop (uint32_t *buf) -{ - return emit_insn (buf, NOP); -} - /* Write LEN instructions from BUF into the inferior memory at *TO. Note instructions are always little endian on AArch64, unlike data. */ @@ -1849,17 +1543,6 @@ append_insns (CORE_ADDR *to, size_t len, const uint32_t *buf) *to += byte_len; } -/* Helper function. Return 1 if VAL can be encoded in BITS bits. */ - -static int -can_encode_int32 (int32_t val, unsigned bits) -{ - /* This must be an arithemic shift. */ - int32_t rest = val >> bits; - - return rest == 0 || rest == -1; -} - /* Sub-class of struct aarch64_insn_data, store information of instruction relocation for fast tracepoint. Visitor can relocate an instruction from BASE.INSN_ADDR to NEW_ADDR and save |