Message ID | 1410998984-20070-1-git-send-email-omair.javaid@linaro.org |
---|---|
State | New |
Headers | show |
On 18 September 2014 05:09, Omair Javaid <omair.javaid@linaro.org> wrote: > 2014-09-18 Omair Javaid <omair.javaid@linaro.org> > > * aarch64-linux-tdep.c (aarch64_linux_init_abi): Install AArch64 > process record handler. > * aarch64-tdep.c (record.h): Include. > (record-full.h): Include. > (submask): New macro. > (bit): New macro. > (bits): New macro. > (REG_ALLOC): New macro. > (MEM_ALLOC): New macro. > (struct aarch64_mem_r): Define. > (aarch64_record_result): New enum. > (struct insn_decode_record): Define. > (insn_decode_record): New typedef. > (aarch64_record_data_proc_reg): Add record handler for data processing > register insns. > (aarch64_record_data_proc_imm): Add record handler for data processing > immediate insns. > (aarch64_record_branch_except_sys): Add record handler for branch, > exception and system insns. > (aarch64_record_load_store): Add record handler for load/store insns. > (aarch64_record_decode_insn_handler): Add record insn decoding function. > (deallocate_reg_mem): Add memory cleanup function for record data. > (aarch64_process_record): Add gdbarch handler for AArch64 process > record. > * aarch64-tdep.h (aarch64_process_record): New extern declaration. > --- > gdb/aarch64-linux-tdep.c | 3 + > gdb/aarch64-tdep.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++ > gdb/aarch64-tdep.h | 3 + > 3 files changed, 584 insertions(+) > > diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c > index e5565a8..5ab7b37 100644 > --- a/gdb/aarch64-linux-tdep.c > +++ b/gdb/aarch64-linux-tdep.c > @@ -401,6 +401,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) > set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand); > set_gdbarch_stap_parse_special_token (gdbarch, > aarch64_stap_parse_special_token); > + > + /* Reversible debugging, process record. */ > + set_gdbarch_process_record (gdbarch, aarch64_process_record); > } > > /* Provide a prototype to silence -Wmissing-prototypes. */ > diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c > index 1898f6b..ed28f68 100644 > --- a/gdb/aarch64-tdep.c > +++ b/gdb/aarch64-tdep.c > @@ -50,6 +50,9 @@ > > #include "vec.h" > > +#include "record.h" > +#include "record-full.h" > + > #include "features/aarch64.c" > > /* Pseudo register base numbers. */ > @@ -2804,3 +2807,578 @@ When on, AArch64 specific debugging is enabled."), > show_aarch64_debug, > &setdebuglist, &showdebuglist); > } > + > +/* AArch64 process record-replay related structures, defines etc. */ > + > +#define submask(x) ((1L << ((x) + 1)) - 1) > +#define bit(obj,st) (((obj) >> (st)) & 1) > +#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st))) > + > +#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \ > + do \ > + { \ > + unsigned int reg_len = LENGTH; \ > + if (reg_len) \ > + { \ > + REGS = XNEWVEC (uint32_t, reg_len); \ > + memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \ > + } \ > + } \ > + while (0) > + > +#define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \ > + do \ > + { \ > + unsigned int mem_len = LENGTH; \ > + if (mem_len) \ > + { \ > + MEMS = XNEWVEC (struct aarch64_mem_r, mem_len); \ > + memcpy(&MEMS->len, &RECORD_BUF[0], \ > + sizeof(struct aarch64_mem_r) * LENGTH); \ > + } \ > + } \ > + while (0) > + > +/* AArch64 memory record structure. */ > +struct aarch64_mem_r > +{ > + uint64_t len; /* Record length. */ > + uint64_t addr; /* Memory address. */ > +}; > + > +enum aarch64_record_result > +{ > + AARCH64_RECORD_SUCCESS, > + AARCH64_RECORD_FAILURE, > + AARCH64_RECORD_UNSUPPORTED > +}; > + > +/* AArch64 instruction record contains opcode of current insn and execution > + state (before entry to decode_insn()), contains list of to-be-modified > + registers and memory blocks (on return from decode_insn()). */ > + > +typedef struct insn_decode_record_t > +{ > + struct gdbarch *gdbarch; > + struct regcache *regcache; > + CORE_ADDR this_addr; > + uint32_t aarch64_insn; > + uint32_t mem_rec_count; > + uint32_t reg_rec_count; > + uint32_t *aarch64_regs; > + struct aarch64_mem_r *aarch64_mems; > +} insn_decode_record; > + > +/* Record handler for data processing - register instructions. */ > +static unsigned int > +aarch64_record_data_proc_reg (insn_decode_record *aarch64_insn_r) > +{ > + uint8_t reg_rd, insn_bits24_27, insn_bits21_23, setflags; > + uint32_t record_buf[4]; > + > + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); > + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); > + insn_bits21_23 = bits (aarch64_insn_r->aarch64_insn, 21, 23); > + > + if (!bit (aarch64_insn_r->aarch64_insn, 28)) > + { > + /* Logical (shifted register). */ > + if (insn_bits24_27 == 0x0a) > + setflags = (bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03); > + /* Add/subtract. */ > + else if (insn_bits24_27 == 0x0b) > + setflags = bit (aarch64_insn_r->aarch64_insn, 29); > + else > + return AARCH64_RECORD_UNSUPPORTED; > + > + record_buf[0] = reg_rd; > + aarch64_insn_r->reg_rec_count = 1; > + if (setflags) > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; > + } > + else > + { > + if (insn_bits24_27 == 0x0b) > + { > + /* Data-processing (3 source). */ > + record_buf[0] = reg_rd; > + aarch64_insn_r->reg_rec_count = 1; > + } > + else if (insn_bits24_27 == 0x0a) > + { > + if (insn_bits21_23 == 0x00) > + { > + /* Add/subtract (with carry). */ > + record_buf[0] = reg_rd; > + aarch64_insn_r->reg_rec_count = 1; > + if (bit (aarch64_insn_r->aarch64_insn, 29)) > + { > + record_buf[1] = AARCH64_CPSR_REGNUM; > + aarch64_insn_r->reg_rec_count = 2; > + } > + } > + else if (insn_bits21_23 == 0x02) > + { > + /* Conditional compare (register) / Conditional compare (immediate). */ > + record_buf[0] = AARCH64_CPSR_REGNUM; > + aarch64_insn_r->reg_rec_count = 1; > + } > + else if (insn_bits21_23 == 0x04 || insn_bits21_23 == 0x06) > + { > + /* CConditional select. */ > + /* Data-processing (2 source). */ > + /* Data-processing (1 source). */ > + record_buf[0] = reg_rd; > + aarch64_insn_r->reg_rec_count = 1; > + } > + else > + return AARCH64_RECORD_UNSUPPORTED; > + } > + } > + > + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, > + record_buf); > + return AARCH64_RECORD_SUCCESS; > +} > + > +/* Record handler for data processing - immediate instructions. */ > +static unsigned int > +aarch64_record_data_proc_imm (insn_decode_record *aarch64_insn_r) > +{ > + uint8_t reg_rd, insn_bit28, insn_bit23, insn_bits24_27, setflags; > + uint32_t record_buf[4]; > + > + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); > + insn_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); > + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); > + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); > + > + /* PC rel addressing / Move wide immediate / BitField / Extract. */ > + if (insn_bits24_27 == 0x00 || insn_bits24_27 == 0x03 || > + (insn_bits24_27 == 0x02 && insn_bit23)) > + { > + record_buf[0] = reg_rd; > + aarch64_insn_r->reg_rec_count = 1; > + } > + else if (insn_bits24_27 == 0x01) > + { > + /* Add/Subtract (immediate). */ > + setflags = bit (aarch64_insn_r->aarch64_insn, 29); > + record_buf[0] = reg_rd; > + aarch64_insn_r->reg_rec_count = 1; > + if (setflags) > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; > + } > + else if (insn_bits24_27 == 0x02 && !insn_bit23) > + { > + /* Logical (immediate). */ > + setflags = bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03; > + record_buf[0] = reg_rd; > + aarch64_insn_r->reg_rec_count = 1; > + if (setflags) > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; > + } > + else > + return AARCH64_RECORD_UNSUPPORTED; > + > + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, > + record_buf); > + return AARCH64_RECORD_SUCCESS; > +} > + > +/* Record handler for branch, exception generation and system instructions. */ > +static unsigned int > +aarch64_record_branch_except_sys (insn_decode_record *aarch64_insn_r) > +{ > + struct gdbarch_tdep *tdep = gdbarch_tdep (aarch64_insn_r->gdbarch); > + uint8_t insn_bits24_27, insn_bits28_31, insn_bits22_23; > + uint32_t record_buf[4]; > + > + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); > + insn_bits28_31 = bits (aarch64_insn_r->aarch64_insn, 28, 31); > + insn_bits22_23 = bits (aarch64_insn_r->aarch64_insn, 22, 23); > + > + if (insn_bits28_31 == 0x0d) > + { > + /* Exception generation instructions. */ > + if (insn_bits24_27 == 0x04) > + return AARCH64_RECORD_UNSUPPORTED; > + /* System instructions. */ > + else if (insn_bits24_27 == 0x05 && insn_bits22_23 == 0x00) > + { > + record_buf[0] = AARCH64_CPSR_REGNUM; > + record_buf[1] = bits (aarch64_insn_r->aarch64_insn, 0, 4); > + aarch64_insn_r->reg_rec_count = 2; > + } > + else if((insn_bits24_27 & 0x0e) == 0x06) > + { > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; > + if (bits (aarch64_insn_r->aarch64_insn, 21, 22) == 0x01) > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; > + } > + else > + return AARCH64_RECORD_UNSUPPORTED; > + } > + else if ((insn_bits28_31 & 0x07) == 0x01 && (insn_bits24_27 & 0x0c) == 0x04) > + { > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; > + if (bit (aarch64_insn_r->aarch64_insn, 31)) > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; > + } > + else > + /* All other types of branch instructions. */ > + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; > + > + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, > + record_buf); > + return AARCH64_RECORD_SUCCESS; > +} > + > +/* Record handler for load and store instructions. */ > +static unsigned int > +aarch64_record_load_store (insn_decode_record *aarch64_insn_r) > +{ > + uint8_t insn_bits24_27, insn_bits28_29, insn_bits10_11; > + uint8_t insn_bit23, insn_bit21; > + uint8_t opc, size_bits, ld_flag, vector_flag; > + uint32_t reg_rn, reg_rt, reg_rt2; > + uint64_t datasize, offset; > + uint32_t record_buf[8]; > + uint64_t record_buf_mem[8]; > + CORE_ADDR address; > + > + insn_bits10_11 = bits (aarch64_insn_r->aarch64_insn, 10, 11); > + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); > + insn_bits28_29 = bits (aarch64_insn_r->aarch64_insn, 28, 29); > + insn_bit21 = bit (aarch64_insn_r->aarch64_insn, 21); > + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); > + ld_flag = bit (aarch64_insn_r->aarch64_insn, 22); > + vector_flag = bit (aarch64_insn_r->aarch64_insn, 26); > + reg_rt = bits (aarch64_insn_r->aarch64_insn, 0, 4); > + reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); > + reg_rt2 = bits (aarch64_insn_r->aarch64_insn, 10, 14); > + size_bits = bits (aarch64_insn_r->aarch64_insn, 30, 31); > + > + /* Load/store exclusive instructions decoding. */ > + if (insn_bits24_27 == 0x08 && insn_bits28_29 == 0x00) > + { > + if (ld_flag) > + { > + record_buf[0] = reg_rt; > + aarch64_insn_r->reg_rec_count = 1; > + if (insn_bit21) > + { > + record_buf[1] = reg_rt2; > + aarch64_insn_r->reg_rec_count = 2; > + } > + } > + else > + { > + if (insn_bit21) > + datasize = (8 << size_bits) * 2; > + else > + datasize = (8 << size_bits); > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, > + &address); > + record_buf_mem[0] = datasize / 8; > + record_buf_mem[1] = address; > + aarch64_insn_r->mem_rec_count = 1; > + if (!insn_bit23) > + { > + /* Save register rs. */ > + record_buf[0] = bits (aarch64_insn_r->aarch64_insn, 16, 20); > + aarch64_insn_r->reg_rec_count = 1; > + } > + } > + } > + /* Load register (literal) instructions decoding. */ > + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x01) > + { > + if (vector_flag) > + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; > + else > + record_buf[0] = reg_rt; > + aarch64_insn_r->reg_rec_count = 1; > + } > + /* All types of load/store pair instructions decoding. */ > + else if ((insn_bits24_27 & 0x0a) == 0x08 && insn_bits28_29 == 0x02) > + { > + if (ld_flag) > + { > + if (vector_flag) > + { > + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; > + record_buf[1] = reg_rt2 + AARCH64_V0_REGNUM; > + } > + else > + { > + record_buf[0] = reg_rt; > + record_buf[1] = reg_rt2; > + } > + aarch64_insn_r->reg_rec_count = 2; > + } > + else > + { > + uint16_t imm7_off; > + imm7_off = bits (aarch64_insn_r->aarch64_insn, 15, 21); > + if (!vector_flag) > + size_bits = size_bits >> 1; > + datasize = 8 << (2 + size_bits); > + offset = (imm7_off & 0x40) ? (~imm7_off & 0x007f) + 1 : imm7_off; > + offset = offset << (2 + size_bits); > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, > + &address); > + if (!((insn_bits24_27 & 0x0b) == 0x08 && insn_bit23)) > + { > + if (imm7_off & 0x40) > + address = address - offset; > + else > + address = address + offset; > + } > + > + record_buf_mem[0] = datasize / 8; > + record_buf_mem[1] = address; > + record_buf_mem[2] = datasize / 8; > + record_buf_mem[3] = address + (datasize / 8); > + aarch64_insn_r->mem_rec_count = 2; > + } > + if (bit (aarch64_insn_r->aarch64_insn, 23)) > + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; > + } > + /* Load/store register (unsigned immediate) instructions. */ > + else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x03) > + { > + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); > + if (!(opc >> 1)) > + if (opc & 0x01) > + ld_flag = 0x01; > + else > + ld_flag = 0x0; > + else > + if (size_bits != 0x03) > + ld_flag = 0x01; > + else > + return AARCH64_RECORD_UNSUPPORTED; > + > + if (!ld_flag) > + { > + offset = bits (aarch64_insn_r->aarch64_insn, 10, 21); > + datasize = 8 << size_bits; > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, > + &address); > + offset = offset << size_bits; > + address = address + offset; > + > + record_buf_mem[0] = datasize >> 3; > + record_buf_mem[1] = address; > + aarch64_insn_r->mem_rec_count = 1; > + } > + else > + { > + if (vector_flag) > + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; > + else > + record_buf[0] = reg_rt; > + aarch64_insn_r->reg_rec_count = 1; > + } > + } > + /* Load/store register (register offset) instructions. */ > + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && > + insn_bits10_11 == 0x02 && insn_bit21) > + { > + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); > + if (!(opc >> 1)) > + if (opc & 0x01) > + ld_flag = 0x01; > + else > + ld_flag = 0x0; > + else > + if (size_bits != 0x03) > + ld_flag = 0x01; > + else > + return AARCH64_RECORD_UNSUPPORTED; > + > + if (!ld_flag) > + { > + uint64_t reg_rm_val; > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, > + bits (aarch64_insn_r->aarch64_insn, 16, 20), ®_rm_val); > + if (bit (aarch64_insn_r->aarch64_insn, 12)) > + offset = reg_rm_val << size_bits; > + else > + offset = reg_rm_val; > + datasize = 8 << size_bits; > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, > + &address); > + address = address + offset; > + record_buf_mem[0] = datasize >> 3; > + record_buf_mem[1] = address; > + aarch64_insn_r->mem_rec_count = 1; > + } > + else > + { > + if (vector_flag) > + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; > + else > + record_buf[0] = reg_rt; > + aarch64_insn_r->reg_rec_count = 1; > + } > + } > + /* Load/store register (immediate) instructions. */ > + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && > + !insn_bit21) > + { > + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); > + if (!(opc >> 1)) > + if (opc & 0x01) > + ld_flag = 0x01; > + else > + ld_flag = 0x0; > + else > + if (size_bits != 0x03) > + ld_flag = 0x01; > + else > + return AARCH64_RECORD_UNSUPPORTED; > + > + if (!ld_flag) > + { > + uint16_t imm9_off; > + imm9_off = bits (aarch64_insn_r->aarch64_insn, 12, 20); > + offset = (imm9_off & 0x0100) ? (((~imm9_off) & 0x01ff) + 1) : imm9_off; > + datasize = 8 << size_bits; > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, > + &address); > + if (insn_bits10_11 != 0x01) > + { > + if (imm9_off & 0x0100) > + address = address - offset; > + else > + address = address + offset; > + } > + record_buf_mem[0] = datasize >> 3; > + record_buf_mem[1] = address; > + aarch64_insn_r->mem_rec_count = 1; > + } > + else > + { > + if (vector_flag) > + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; > + else > + record_buf[0] = reg_rt; > + aarch64_insn_r->reg_rec_count = 1; > + } > + if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03) > + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; > + } > + /* Advanced SIMD load/store instructions. */ > + else > + return AARCH64_RECORD_UNSUPPORTED; > + > + MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count, > + record_buf_mem); > + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, > + record_buf); > + return AARCH64_RECORD_SUCCESS; > +} > +/* Decodes insns type and invokes its record handler. */ > + > +static unsigned int > +aarch64_record_decode_insn_handler (insn_decode_record *aarch64_insn_r) > +{ > + uint32_t ins_bit25, ins_bit26, ins_bit27, ins_bit28; > + > + ins_bit25 = bit (aarch64_insn_r->aarch64_insn, 25); > + ins_bit26 = bit (aarch64_insn_r->aarch64_insn, 26); > + ins_bit27 = bit (aarch64_insn_r->aarch64_insn, 27); > + ins_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); > + > + /* Data processing - immediate instructions. */ > + if (!ins_bit26 && !ins_bit27 && ins_bit28) > + return aarch64_record_data_proc_imm (aarch64_insn_r); > + > + /* Branch, exception generation and system instructions. */ > + if (ins_bit26 && !ins_bit27 && ins_bit28) > + return aarch64_record_branch_except_sys (aarch64_insn_r); > + > + /* Load and store instructions. */ > + if (!ins_bit25 && ins_bit27) > + return aarch64_record_load_store (aarch64_insn_r); > + > + /* Data processing - register instructions. */ > + if (ins_bit25 && !ins_bit26 && ins_bit27) > + return aarch64_record_data_proc_reg (aarch64_insn_r); > + > + /* Data processing - SIMD and floating point instructions. */ > + if (ins_bit25 && ins_bit26 && ins_bit27) > + return AARCH64_RECORD_UNSUPPORTED; > + > + return AARCH64_RECORD_UNSUPPORTED; > +} > + > +/* Cleans up local record registers and memory allocations. */ > + > +static void > +deallocate_reg_mem (insn_decode_record *record) > +{ > + xfree (record->aarch64_regs); > + xfree (record->aarch64_mems); > +} > + > +/* Parse the current instruction and record the values of the registers and > + memory that will be changed in current instruction to record_arch_list > + return -1 if something is wrong. */ > + > +int > +aarch64_process_record (struct gdbarch *gdbarch, struct regcache *regcache, > + CORE_ADDR insn_addr) > +{ > + uint32_t rec_no = 0; > + uint8_t insn_size = 4; > + uint32_t ret = 0; > + ULONGEST t_bit = 0, insn_id = 0; > + gdb_byte buf[insn_size]; > + insn_decode_record aarch64_record; > + > + memset (&buf[0], 0, insn_size); > + memset (&aarch64_record, 0, sizeof (insn_decode_record)); > + target_read_memory (insn_addr, &buf[0], insn_size); > + aarch64_record.aarch64_insn = (uint32_t) extract_unsigned_integer (&buf[0], > + insn_size, gdbarch_byte_order (gdbarch)); > + aarch64_record.regcache = regcache; > + aarch64_record.this_addr = insn_addr; > + aarch64_record.gdbarch = gdbarch; > + > + ret = aarch64_record_decode_insn_handler (&aarch64_record); > + if (ret == AARCH64_RECORD_UNSUPPORTED) > + { > + printf_unfiltered (_("Process record does not support instruction " > + "0x%0x at address %s.\n"),aarch64_record.aarch64_insn, > + paddress (gdbarch, insn_addr)); > + ret = -1; > + } > + > + if (0 == ret) > + { > + /* Record registers. */ > + record_full_arch_list_add_reg (aarch64_record.regcache, AARCH64_PC_REGNUM); > + if (aarch64_record.aarch64_regs) > + for (rec_no = 0; rec_no < aarch64_record.reg_rec_count; rec_no++) > + if (record_full_arch_list_add_reg (aarch64_record.regcache, > + aarch64_record.aarch64_regs[rec_no])) > + ret = -1; > + > + /* Record memories. */ > + if (aarch64_record.aarch64_mems) > + for (rec_no = 0; rec_no < aarch64_record.mem_rec_count; rec_no++) > + if (record_full_arch_list_add_mem > + ((CORE_ADDR)aarch64_record.aarch64_mems[rec_no].addr, > + aarch64_record.aarch64_mems[rec_no].len)) > + ret = -1; > + > + if (record_full_arch_list_add_end ()) > + ret = -1; > + } > + > + deallocate_reg_mem (&aarch64_record); > + return ret; > +} > diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h > index 78fb779..3dd3dcc 100644 > --- a/gdb/aarch64-tdep.h > +++ b/gdb/aarch64-tdep.h > @@ -90,4 +90,7 @@ struct gdbarch_tdep > struct type *vnb_type; > }; > > +extern int aarch64_process_record (struct gdbarch *gdbarch, > + struct regcache *regcache, CORE_ADDR addr); > + > #endif /* aarch64-tdep.h */ > -- > 1.9.1 > Ping! Kindly help me approve this patch series.
On 19 September 2014 03:28, Omair Javaid <omair.javaid@linaro.org> wrote: > On 18 September 2014 05:09, Omair Javaid <omair.javaid@linaro.org> wrote: >> 2014-09-18 Omair Javaid <omair.javaid@linaro.org> >> >> * aarch64-linux-tdep.c (aarch64_linux_init_abi): Install AArch64 >> process record handler. >> * aarch64-tdep.c (record.h): Include. >> (record-full.h): Include. >> (submask): New macro. >> (bit): New macro. >> (bits): New macro. >> (REG_ALLOC): New macro. >> (MEM_ALLOC): New macro. >> (struct aarch64_mem_r): Define. >> (aarch64_record_result): New enum. >> (struct insn_decode_record): Define. >> (insn_decode_record): New typedef. >> (aarch64_record_data_proc_reg): Add record handler for data processing >> register insns. >> (aarch64_record_data_proc_imm): Add record handler for data processing >> immediate insns. >> (aarch64_record_branch_except_sys): Add record handler for branch, >> exception and system insns. >> (aarch64_record_load_store): Add record handler for load/store insns. >> (aarch64_record_decode_insn_handler): Add record insn decoding function. >> (deallocate_reg_mem): Add memory cleanup function for record data. >> (aarch64_process_record): Add gdbarch handler for AArch64 process >> record. >> * aarch64-tdep.h (aarch64_process_record): New extern declaration. >> --- >> gdb/aarch64-linux-tdep.c | 3 + >> gdb/aarch64-tdep.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++ >> gdb/aarch64-tdep.h | 3 + >> 3 files changed, 584 insertions(+) >> >> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c >> index e5565a8..5ab7b37 100644 >> --- a/gdb/aarch64-linux-tdep.c >> +++ b/gdb/aarch64-linux-tdep.c >> @@ -401,6 +401,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) >> set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand); >> set_gdbarch_stap_parse_special_token (gdbarch, >> aarch64_stap_parse_special_token); >> + >> + /* Reversible debugging, process record. */ >> + set_gdbarch_process_record (gdbarch, aarch64_process_record); >> } >> >> /* Provide a prototype to silence -Wmissing-prototypes. */ >> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c >> index 1898f6b..ed28f68 100644 >> --- a/gdb/aarch64-tdep.c >> +++ b/gdb/aarch64-tdep.c >> @@ -50,6 +50,9 @@ >> >> #include "vec.h" >> >> +#include "record.h" >> +#include "record-full.h" >> + >> #include "features/aarch64.c" >> >> /* Pseudo register base numbers. */ >> @@ -2804,3 +2807,578 @@ When on, AArch64 specific debugging is enabled."), >> show_aarch64_debug, >> &setdebuglist, &showdebuglist); >> } >> + >> +/* AArch64 process record-replay related structures, defines etc. */ >> + >> +#define submask(x) ((1L << ((x) + 1)) - 1) >> +#define bit(obj,st) (((obj) >> (st)) & 1) >> +#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st))) >> + >> +#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \ >> + do \ >> + { \ >> + unsigned int reg_len = LENGTH; \ >> + if (reg_len) \ >> + { \ >> + REGS = XNEWVEC (uint32_t, reg_len); \ >> + memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \ >> + } \ >> + } \ >> + while (0) >> + >> +#define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \ >> + do \ >> + { \ >> + unsigned int mem_len = LENGTH; \ >> + if (mem_len) \ >> + { \ >> + MEMS = XNEWVEC (struct aarch64_mem_r, mem_len); \ >> + memcpy(&MEMS->len, &RECORD_BUF[0], \ >> + sizeof(struct aarch64_mem_r) * LENGTH); \ >> + } \ >> + } \ >> + while (0) >> + >> +/* AArch64 memory record structure. */ >> +struct aarch64_mem_r >> +{ >> + uint64_t len; /* Record length. */ >> + uint64_t addr; /* Memory address. */ >> +}; >> + >> +enum aarch64_record_result >> +{ >> + AARCH64_RECORD_SUCCESS, >> + AARCH64_RECORD_FAILURE, >> + AARCH64_RECORD_UNSUPPORTED >> +}; >> + >> +/* AArch64 instruction record contains opcode of current insn and execution >> + state (before entry to decode_insn()), contains list of to-be-modified >> + registers and memory blocks (on return from decode_insn()). */ >> + >> +typedef struct insn_decode_record_t >> +{ >> + struct gdbarch *gdbarch; >> + struct regcache *regcache; >> + CORE_ADDR this_addr; >> + uint32_t aarch64_insn; >> + uint32_t mem_rec_count; >> + uint32_t reg_rec_count; >> + uint32_t *aarch64_regs; >> + struct aarch64_mem_r *aarch64_mems; >> +} insn_decode_record; >> + >> +/* Record handler for data processing - register instructions. */ >> +static unsigned int >> +aarch64_record_data_proc_reg (insn_decode_record *aarch64_insn_r) >> +{ >> + uint8_t reg_rd, insn_bits24_27, insn_bits21_23, setflags; >> + uint32_t record_buf[4]; >> + >> + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); >> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >> + insn_bits21_23 = bits (aarch64_insn_r->aarch64_insn, 21, 23); >> + >> + if (!bit (aarch64_insn_r->aarch64_insn, 28)) >> + { >> + /* Logical (shifted register). */ >> + if (insn_bits24_27 == 0x0a) >> + setflags = (bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03); >> + /* Add/subtract. */ >> + else if (insn_bits24_27 == 0x0b) >> + setflags = bit (aarch64_insn_r->aarch64_insn, 29); >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + >> + record_buf[0] = reg_rd; >> + aarch64_insn_r->reg_rec_count = 1; >> + if (setflags) >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; >> + } >> + else >> + { >> + if (insn_bits24_27 == 0x0b) >> + { >> + /* Data-processing (3 source). */ >> + record_buf[0] = reg_rd; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + else if (insn_bits24_27 == 0x0a) >> + { >> + if (insn_bits21_23 == 0x00) >> + { >> + /* Add/subtract (with carry). */ >> + record_buf[0] = reg_rd; >> + aarch64_insn_r->reg_rec_count = 1; >> + if (bit (aarch64_insn_r->aarch64_insn, 29)) >> + { >> + record_buf[1] = AARCH64_CPSR_REGNUM; >> + aarch64_insn_r->reg_rec_count = 2; >> + } >> + } >> + else if (insn_bits21_23 == 0x02) >> + { >> + /* Conditional compare (register) / Conditional compare (immediate). */ >> + record_buf[0] = AARCH64_CPSR_REGNUM; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + else if (insn_bits21_23 == 0x04 || insn_bits21_23 == 0x06) >> + { >> + /* CConditional select. */ >> + /* Data-processing (2 source). */ >> + /* Data-processing (1 source). */ >> + record_buf[0] = reg_rd; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + } >> + } >> + >> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >> + record_buf); >> + return AARCH64_RECORD_SUCCESS; >> +} >> + >> +/* Record handler for data processing - immediate instructions. */ >> +static unsigned int >> +aarch64_record_data_proc_imm (insn_decode_record *aarch64_insn_r) >> +{ >> + uint8_t reg_rd, insn_bit28, insn_bit23, insn_bits24_27, setflags; >> + uint32_t record_buf[4]; >> + >> + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); >> + insn_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); >> + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); >> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >> + >> + /* PC rel addressing / Move wide immediate / BitField / Extract. */ >> + if (insn_bits24_27 == 0x00 || insn_bits24_27 == 0x03 || >> + (insn_bits24_27 == 0x02 && insn_bit23)) >> + { >> + record_buf[0] = reg_rd; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + else if (insn_bits24_27 == 0x01) >> + { >> + /* Add/Subtract (immediate). */ >> + setflags = bit (aarch64_insn_r->aarch64_insn, 29); >> + record_buf[0] = reg_rd; >> + aarch64_insn_r->reg_rec_count = 1; >> + if (setflags) >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; >> + } >> + else if (insn_bits24_27 == 0x02 && !insn_bit23) >> + { >> + /* Logical (immediate). */ >> + setflags = bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03; >> + record_buf[0] = reg_rd; >> + aarch64_insn_r->reg_rec_count = 1; >> + if (setflags) >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; >> + } >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + >> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >> + record_buf); >> + return AARCH64_RECORD_SUCCESS; >> +} >> + >> +/* Record handler for branch, exception generation and system instructions. */ >> +static unsigned int >> +aarch64_record_branch_except_sys (insn_decode_record *aarch64_insn_r) >> +{ >> + struct gdbarch_tdep *tdep = gdbarch_tdep (aarch64_insn_r->gdbarch); >> + uint8_t insn_bits24_27, insn_bits28_31, insn_bits22_23; >> + uint32_t record_buf[4]; >> + >> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >> + insn_bits28_31 = bits (aarch64_insn_r->aarch64_insn, 28, 31); >> + insn_bits22_23 = bits (aarch64_insn_r->aarch64_insn, 22, 23); >> + >> + if (insn_bits28_31 == 0x0d) >> + { >> + /* Exception generation instructions. */ >> + if (insn_bits24_27 == 0x04) >> + return AARCH64_RECORD_UNSUPPORTED; >> + /* System instructions. */ >> + else if (insn_bits24_27 == 0x05 && insn_bits22_23 == 0x00) >> + { >> + record_buf[0] = AARCH64_CPSR_REGNUM; >> + record_buf[1] = bits (aarch64_insn_r->aarch64_insn, 0, 4); >> + aarch64_insn_r->reg_rec_count = 2; >> + } >> + else if((insn_bits24_27 & 0x0e) == 0x06) >> + { >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; >> + if (bits (aarch64_insn_r->aarch64_insn, 21, 22) == 0x01) >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; >> + } >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + } >> + else if ((insn_bits28_31 & 0x07) == 0x01 && (insn_bits24_27 & 0x0c) == 0x04) >> + { >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; >> + if (bit (aarch64_insn_r->aarch64_insn, 31)) >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; >> + } >> + else >> + /* All other types of branch instructions. */ >> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; >> + >> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >> + record_buf); >> + return AARCH64_RECORD_SUCCESS; >> +} >> + >> +/* Record handler for load and store instructions. */ >> +static unsigned int >> +aarch64_record_load_store (insn_decode_record *aarch64_insn_r) >> +{ >> + uint8_t insn_bits24_27, insn_bits28_29, insn_bits10_11; >> + uint8_t insn_bit23, insn_bit21; >> + uint8_t opc, size_bits, ld_flag, vector_flag; >> + uint32_t reg_rn, reg_rt, reg_rt2; >> + uint64_t datasize, offset; >> + uint32_t record_buf[8]; >> + uint64_t record_buf_mem[8]; >> + CORE_ADDR address; >> + >> + insn_bits10_11 = bits (aarch64_insn_r->aarch64_insn, 10, 11); >> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >> + insn_bits28_29 = bits (aarch64_insn_r->aarch64_insn, 28, 29); >> + insn_bit21 = bit (aarch64_insn_r->aarch64_insn, 21); >> + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); >> + ld_flag = bit (aarch64_insn_r->aarch64_insn, 22); >> + vector_flag = bit (aarch64_insn_r->aarch64_insn, 26); >> + reg_rt = bits (aarch64_insn_r->aarch64_insn, 0, 4); >> + reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); >> + reg_rt2 = bits (aarch64_insn_r->aarch64_insn, 10, 14); >> + size_bits = bits (aarch64_insn_r->aarch64_insn, 30, 31); >> + >> + /* Load/store exclusive instructions decoding. */ >> + if (insn_bits24_27 == 0x08 && insn_bits28_29 == 0x00) >> + { >> + if (ld_flag) >> + { >> + record_buf[0] = reg_rt; >> + aarch64_insn_r->reg_rec_count = 1; >> + if (insn_bit21) >> + { >> + record_buf[1] = reg_rt2; >> + aarch64_insn_r->reg_rec_count = 2; >> + } >> + } >> + else >> + { >> + if (insn_bit21) >> + datasize = (8 << size_bits) * 2; >> + else >> + datasize = (8 << size_bits); >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >> + &address); >> + record_buf_mem[0] = datasize / 8; >> + record_buf_mem[1] = address; >> + aarch64_insn_r->mem_rec_count = 1; >> + if (!insn_bit23) >> + { >> + /* Save register rs. */ >> + record_buf[0] = bits (aarch64_insn_r->aarch64_insn, 16, 20); >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + } >> + } >> + /* Load register (literal) instructions decoding. */ >> + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x01) >> + { >> + if (vector_flag) >> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >> + else >> + record_buf[0] = reg_rt; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + /* All types of load/store pair instructions decoding. */ >> + else if ((insn_bits24_27 & 0x0a) == 0x08 && insn_bits28_29 == 0x02) >> + { >> + if (ld_flag) >> + { >> + if (vector_flag) >> + { >> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >> + record_buf[1] = reg_rt2 + AARCH64_V0_REGNUM; >> + } >> + else >> + { >> + record_buf[0] = reg_rt; >> + record_buf[1] = reg_rt2; >> + } >> + aarch64_insn_r->reg_rec_count = 2; >> + } >> + else >> + { >> + uint16_t imm7_off; >> + imm7_off = bits (aarch64_insn_r->aarch64_insn, 15, 21); >> + if (!vector_flag) >> + size_bits = size_bits >> 1; >> + datasize = 8 << (2 + size_bits); >> + offset = (imm7_off & 0x40) ? (~imm7_off & 0x007f) + 1 : imm7_off; >> + offset = offset << (2 + size_bits); >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >> + &address); >> + if (!((insn_bits24_27 & 0x0b) == 0x08 && insn_bit23)) >> + { >> + if (imm7_off & 0x40) >> + address = address - offset; >> + else >> + address = address + offset; >> + } >> + >> + record_buf_mem[0] = datasize / 8; >> + record_buf_mem[1] = address; >> + record_buf_mem[2] = datasize / 8; >> + record_buf_mem[3] = address + (datasize / 8); >> + aarch64_insn_r->mem_rec_count = 2; >> + } >> + if (bit (aarch64_insn_r->aarch64_insn, 23)) >> + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; >> + } >> + /* Load/store register (unsigned immediate) instructions. */ >> + else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x03) >> + { >> + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); >> + if (!(opc >> 1)) >> + if (opc & 0x01) >> + ld_flag = 0x01; >> + else >> + ld_flag = 0x0; >> + else >> + if (size_bits != 0x03) >> + ld_flag = 0x01; >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + >> + if (!ld_flag) >> + { >> + offset = bits (aarch64_insn_r->aarch64_insn, 10, 21); >> + datasize = 8 << size_bits; >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >> + &address); >> + offset = offset << size_bits; >> + address = address + offset; >> + >> + record_buf_mem[0] = datasize >> 3; >> + record_buf_mem[1] = address; >> + aarch64_insn_r->mem_rec_count = 1; >> + } >> + else >> + { >> + if (vector_flag) >> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >> + else >> + record_buf[0] = reg_rt; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + } >> + /* Load/store register (register offset) instructions. */ >> + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && >> + insn_bits10_11 == 0x02 && insn_bit21) >> + { >> + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); >> + if (!(opc >> 1)) >> + if (opc & 0x01) >> + ld_flag = 0x01; >> + else >> + ld_flag = 0x0; >> + else >> + if (size_bits != 0x03) >> + ld_flag = 0x01; >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + >> + if (!ld_flag) >> + { >> + uint64_t reg_rm_val; >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, >> + bits (aarch64_insn_r->aarch64_insn, 16, 20), ®_rm_val); >> + if (bit (aarch64_insn_r->aarch64_insn, 12)) >> + offset = reg_rm_val << size_bits; >> + else >> + offset = reg_rm_val; >> + datasize = 8 << size_bits; >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >> + &address); >> + address = address + offset; >> + record_buf_mem[0] = datasize >> 3; >> + record_buf_mem[1] = address; >> + aarch64_insn_r->mem_rec_count = 1; >> + } >> + else >> + { >> + if (vector_flag) >> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >> + else >> + record_buf[0] = reg_rt; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + } >> + /* Load/store register (immediate) instructions. */ >> + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && >> + !insn_bit21) >> + { >> + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); >> + if (!(opc >> 1)) >> + if (opc & 0x01) >> + ld_flag = 0x01; >> + else >> + ld_flag = 0x0; >> + else >> + if (size_bits != 0x03) >> + ld_flag = 0x01; >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + >> + if (!ld_flag) >> + { >> + uint16_t imm9_off; >> + imm9_off = bits (aarch64_insn_r->aarch64_insn, 12, 20); >> + offset = (imm9_off & 0x0100) ? (((~imm9_off) & 0x01ff) + 1) : imm9_off; >> + datasize = 8 << size_bits; >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >> + &address); >> + if (insn_bits10_11 != 0x01) >> + { >> + if (imm9_off & 0x0100) >> + address = address - offset; >> + else >> + address = address + offset; >> + } >> + record_buf_mem[0] = datasize >> 3; >> + record_buf_mem[1] = address; >> + aarch64_insn_r->mem_rec_count = 1; >> + } >> + else >> + { >> + if (vector_flag) >> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >> + else >> + record_buf[0] = reg_rt; >> + aarch64_insn_r->reg_rec_count = 1; >> + } >> + if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03) >> + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; >> + } >> + /* Advanced SIMD load/store instructions. */ >> + else >> + return AARCH64_RECORD_UNSUPPORTED; >> + >> + MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count, >> + record_buf_mem); >> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >> + record_buf); >> + return AARCH64_RECORD_SUCCESS; >> +} >> +/* Decodes insns type and invokes its record handler. */ >> + >> +static unsigned int >> +aarch64_record_decode_insn_handler (insn_decode_record *aarch64_insn_r) >> +{ >> + uint32_t ins_bit25, ins_bit26, ins_bit27, ins_bit28; >> + >> + ins_bit25 = bit (aarch64_insn_r->aarch64_insn, 25); >> + ins_bit26 = bit (aarch64_insn_r->aarch64_insn, 26); >> + ins_bit27 = bit (aarch64_insn_r->aarch64_insn, 27); >> + ins_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); >> + >> + /* Data processing - immediate instructions. */ >> + if (!ins_bit26 && !ins_bit27 && ins_bit28) >> + return aarch64_record_data_proc_imm (aarch64_insn_r); >> + >> + /* Branch, exception generation and system instructions. */ >> + if (ins_bit26 && !ins_bit27 && ins_bit28) >> + return aarch64_record_branch_except_sys (aarch64_insn_r); >> + >> + /* Load and store instructions. */ >> + if (!ins_bit25 && ins_bit27) >> + return aarch64_record_load_store (aarch64_insn_r); >> + >> + /* Data processing - register instructions. */ >> + if (ins_bit25 && !ins_bit26 && ins_bit27) >> + return aarch64_record_data_proc_reg (aarch64_insn_r); >> + >> + /* Data processing - SIMD and floating point instructions. */ >> + if (ins_bit25 && ins_bit26 && ins_bit27) >> + return AARCH64_RECORD_UNSUPPORTED; >> + >> + return AARCH64_RECORD_UNSUPPORTED; >> +} >> + >> +/* Cleans up local record registers and memory allocations. */ >> + >> +static void >> +deallocate_reg_mem (insn_decode_record *record) >> +{ >> + xfree (record->aarch64_regs); >> + xfree (record->aarch64_mems); >> +} >> + >> +/* Parse the current instruction and record the values of the registers and >> + memory that will be changed in current instruction to record_arch_list >> + return -1 if something is wrong. */ >> + >> +int >> +aarch64_process_record (struct gdbarch *gdbarch, struct regcache *regcache, >> + CORE_ADDR insn_addr) >> +{ >> + uint32_t rec_no = 0; >> + uint8_t insn_size = 4; >> + uint32_t ret = 0; >> + ULONGEST t_bit = 0, insn_id = 0; >> + gdb_byte buf[insn_size]; >> + insn_decode_record aarch64_record; >> + >> + memset (&buf[0], 0, insn_size); >> + memset (&aarch64_record, 0, sizeof (insn_decode_record)); >> + target_read_memory (insn_addr, &buf[0], insn_size); >> + aarch64_record.aarch64_insn = (uint32_t) extract_unsigned_integer (&buf[0], >> + insn_size, gdbarch_byte_order (gdbarch)); >> + aarch64_record.regcache = regcache; >> + aarch64_record.this_addr = insn_addr; >> + aarch64_record.gdbarch = gdbarch; >> + >> + ret = aarch64_record_decode_insn_handler (&aarch64_record); >> + if (ret == AARCH64_RECORD_UNSUPPORTED) >> + { >> + printf_unfiltered (_("Process record does not support instruction " >> + "0x%0x at address %s.\n"),aarch64_record.aarch64_insn, >> + paddress (gdbarch, insn_addr)); >> + ret = -1; >> + } >> + >> + if (0 == ret) >> + { >> + /* Record registers. */ >> + record_full_arch_list_add_reg (aarch64_record.regcache, AARCH64_PC_REGNUM); >> + if (aarch64_record.aarch64_regs) >> + for (rec_no = 0; rec_no < aarch64_record.reg_rec_count; rec_no++) >> + if (record_full_arch_list_add_reg (aarch64_record.regcache, >> + aarch64_record.aarch64_regs[rec_no])) >> + ret = -1; >> + >> + /* Record memories. */ >> + if (aarch64_record.aarch64_mems) >> + for (rec_no = 0; rec_no < aarch64_record.mem_rec_count; rec_no++) >> + if (record_full_arch_list_add_mem >> + ((CORE_ADDR)aarch64_record.aarch64_mems[rec_no].addr, >> + aarch64_record.aarch64_mems[rec_no].len)) >> + ret = -1; >> + >> + if (record_full_arch_list_add_end ()) >> + ret = -1; >> + } >> + >> + deallocate_reg_mem (&aarch64_record); >> + return ret; >> +} >> diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h >> index 78fb779..3dd3dcc 100644 >> --- a/gdb/aarch64-tdep.h >> +++ b/gdb/aarch64-tdep.h >> @@ -90,4 +90,7 @@ struct gdbarch_tdep >> struct type *vnb_type; >> }; >> >> +extern int aarch64_process_record (struct gdbarch *gdbarch, >> + struct regcache *regcache, CORE_ADDR addr); >> + >> #endif /* aarch64-tdep.h */ >> -- >> 1.9.1 >> > > Ping! Kindly help me approve this patch series. ping!
On 14/10/2014 17:47, Omair Javaid wrote: > On 19 September 2014 03:28, Omair Javaid <omair.javaid@linaro.org> wrote: >> On 18 September 2014 05:09, Omair Javaid <omair.javaid@linaro.org> wrote: >>> 2014-09-18 Omair Javaid <omair.javaid@linaro.org> >>> >>> * aarch64-linux-tdep.c (aarch64_linux_init_abi): Install AArch64 >>> process record handler. >>> * aarch64-tdep.c (record.h): Include. >>> (record-full.h): Include. >>> (submask): New macro. >>> (bit): New macro. >>> (bits): New macro. >>> (REG_ALLOC): New macro. >>> (MEM_ALLOC): New macro. >>> (struct aarch64_mem_r): Define. >>> (aarch64_record_result): New enum. >>> (struct insn_decode_record): Define. >>> (insn_decode_record): New typedef. >>> (aarch64_record_data_proc_reg): Add record handler for data processing >>> register insns. >>> (aarch64_record_data_proc_imm): Add record handler for data processing >>> immediate insns. >>> (aarch64_record_branch_except_sys): Add record handler for branch, >>> exception and system insns. >>> (aarch64_record_load_store): Add record handler for load/store insns. >>> (aarch64_record_decode_insn_handler): Add record insn decoding function. >>> (deallocate_reg_mem): Add memory cleanup function for record data. >>> (aarch64_process_record): Add gdbarch handler for AArch64 process >>> record. >>> * aarch64-tdep.h (aarch64_process_record): New extern declaration. >>> --- >>> gdb/aarch64-linux-tdep.c | 3 + >>> gdb/aarch64-tdep.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++ >>> gdb/aarch64-tdep.h | 3 + >>> 3 files changed, 584 insertions(+) >>> >>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c >>> index e5565a8..5ab7b37 100644 >>> --- a/gdb/aarch64-linux-tdep.c >>> +++ b/gdb/aarch64-linux-tdep.c >>> @@ -401,6 +401,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) >>> set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand); >>> set_gdbarch_stap_parse_special_token (gdbarch, >>> aarch64_stap_parse_special_token); >>> + >>> + /* Reversible debugging, process record. */ >>> + set_gdbarch_process_record (gdbarch, aarch64_process_record); >>> } >>> >>> /* Provide a prototype to silence -Wmissing-prototypes. */ >>> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c >>> index 1898f6b..ed28f68 100644 >>> --- a/gdb/aarch64-tdep.c >>> +++ b/gdb/aarch64-tdep.c >>> @@ -50,6 +50,9 @@ >>> >>> #include "vec.h" >>> >>> +#include "record.h" >>> +#include "record-full.h" >>> + >>> #include "features/aarch64.c" >>> >>> /* Pseudo register base numbers. */ >>> @@ -2804,3 +2807,578 @@ When on, AArch64 specific debugging is enabled."), >>> show_aarch64_debug, >>> &setdebuglist, &showdebuglist); >>> } >>> + >>> +/* AArch64 process record-replay related structures, defines etc. */ >>> + >>> +#define submask(x) ((1L << ((x) + 1)) - 1) >>> +#define bit(obj,st) (((obj) >> (st)) & 1) >>> +#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st))) >>> + >>> +#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \ >>> + do \ >>> + { \ >>> + unsigned int reg_len = LENGTH; \ >>> + if (reg_len) \ >>> + { \ >>> + REGS = XNEWVEC (uint32_t, reg_len); \ >>> + memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \ >>> + } \ >>> + } \ >>> + while (0) >>> + >>> +#define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \ >>> + do \ >>> + { \ >>> + unsigned int mem_len = LENGTH; \ >>> + if (mem_len) \ >>> + { \ >>> + MEMS = XNEWVEC (struct aarch64_mem_r, mem_len); \ >>> + memcpy(&MEMS->len, &RECORD_BUF[0], \ >>> + sizeof(struct aarch64_mem_r) * LENGTH); \ >>> + } \ >>> + } \ >>> + while (0) >>> + >>> +/* AArch64 memory record structure. */ >>> +struct aarch64_mem_r >>> +{ >>> + uint64_t len; /* Record length. */ >>> + uint64_t addr; /* Memory address. */ >>> +}; >>> + >>> +enum aarch64_record_result >>> +{ >>> + AARCH64_RECORD_SUCCESS, >>> + AARCH64_RECORD_FAILURE, >>> + AARCH64_RECORD_UNSUPPORTED >>> +}; >>> + >>> +/* AArch64 instruction record contains opcode of current insn and execution >>> + state (before entry to decode_insn()), contains list of to-be-modified >>> + registers and memory blocks (on return from decode_insn()). */ >>> + >>> +typedef struct insn_decode_record_t >>> +{ >>> + struct gdbarch *gdbarch; >>> + struct regcache *regcache; >>> + CORE_ADDR this_addr; >>> + uint32_t aarch64_insn; >>> + uint32_t mem_rec_count; >>> + uint32_t reg_rec_count; >>> + uint32_t *aarch64_regs; >>> + struct aarch64_mem_r *aarch64_mems; >>> +} insn_decode_record; >>> + >>> +/* Record handler for data processing - register instructions. */ >>> +static unsigned int >>> +aarch64_record_data_proc_reg (insn_decode_record *aarch64_insn_r) >>> +{ >>> + uint8_t reg_rd, insn_bits24_27, insn_bits21_23, setflags; >>> + uint32_t record_buf[4]; >>> + >>> + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); >>> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >>> + insn_bits21_23 = bits (aarch64_insn_r->aarch64_insn, 21, 23); >>> + >>> + if (!bit (aarch64_insn_r->aarch64_insn, 28)) >>> + { >>> + /* Logical (shifted register). */ >>> + if (insn_bits24_27 == 0x0a) >>> + setflags = (bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03); >>> + /* Add/subtract. */ >>> + else if (insn_bits24_27 == 0x0b) >>> + setflags = bit (aarch64_insn_r->aarch64_insn, 29); >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + >>> + record_buf[0] = reg_rd; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + if (setflags) >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; >>> + } >>> + else >>> + { >>> + if (insn_bits24_27 == 0x0b) >>> + { >>> + /* Data-processing (3 source). */ >>> + record_buf[0] = reg_rd; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + else if (insn_bits24_27 == 0x0a) >>> + { >>> + if (insn_bits21_23 == 0x00) >>> + { >>> + /* Add/subtract (with carry). */ >>> + record_buf[0] = reg_rd; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + if (bit (aarch64_insn_r->aarch64_insn, 29)) >>> + { >>> + record_buf[1] = AARCH64_CPSR_REGNUM; >>> + aarch64_insn_r->reg_rec_count = 2; >>> + } >>> + } >>> + else if (insn_bits21_23 == 0x02) >>> + { >>> + /* Conditional compare (register) / Conditional compare (immediate). */ >>> + record_buf[0] = AARCH64_CPSR_REGNUM; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + else if (insn_bits21_23 == 0x04 || insn_bits21_23 == 0x06) >>> + { >>> + /* CConditional select. */ >>> + /* Data-processing (2 source). */ >>> + /* Data-processing (1 source). */ >>> + record_buf[0] = reg_rd; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + } >>> + } >>> + >>> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >>> + record_buf); >>> + return AARCH64_RECORD_SUCCESS; >>> +} >>> + >>> +/* Record handler for data processing - immediate instructions. */ >>> +static unsigned int >>> +aarch64_record_data_proc_imm (insn_decode_record *aarch64_insn_r) >>> +{ >>> + uint8_t reg_rd, insn_bit28, insn_bit23, insn_bits24_27, setflags; >>> + uint32_t record_buf[4]; >>> + >>> + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); >>> + insn_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); >>> + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); >>> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >>> + >>> + /* PC rel addressing / Move wide immediate / BitField / Extract. */ >>> + if (insn_bits24_27 == 0x00 || insn_bits24_27 == 0x03 || >>> + (insn_bits24_27 == 0x02 && insn_bit23)) >>> + { >>> + record_buf[0] = reg_rd; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + else if (insn_bits24_27 == 0x01) >>> + { >>> + /* Add/Subtract (immediate). */ >>> + setflags = bit (aarch64_insn_r->aarch64_insn, 29); >>> + record_buf[0] = reg_rd; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + if (setflags) >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; >>> + } >>> + else if (insn_bits24_27 == 0x02 && !insn_bit23) >>> + { >>> + /* Logical (immediate). */ >>> + setflags = bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03; >>> + record_buf[0] = reg_rd; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + if (setflags) >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; >>> + } >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + >>> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >>> + record_buf); >>> + return AARCH64_RECORD_SUCCESS; >>> +} >>> + >>> +/* Record handler for branch, exception generation and system instructions. */ >>> +static unsigned int >>> +aarch64_record_branch_except_sys (insn_decode_record *aarch64_insn_r) >>> +{ >>> + struct gdbarch_tdep *tdep = gdbarch_tdep (aarch64_insn_r->gdbarch); >>> + uint8_t insn_bits24_27, insn_bits28_31, insn_bits22_23; >>> + uint32_t record_buf[4]; >>> + >>> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >>> + insn_bits28_31 = bits (aarch64_insn_r->aarch64_insn, 28, 31); >>> + insn_bits22_23 = bits (aarch64_insn_r->aarch64_insn, 22, 23); >>> + >>> + if (insn_bits28_31 == 0x0d) >>> + { >>> + /* Exception generation instructions. */ >>> + if (insn_bits24_27 == 0x04) >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + /* System instructions. */ >>> + else if (insn_bits24_27 == 0x05 && insn_bits22_23 == 0x00) >>> + { >>> + record_buf[0] = AARCH64_CPSR_REGNUM; >>> + record_buf[1] = bits (aarch64_insn_r->aarch64_insn, 0, 4); >>> + aarch64_insn_r->reg_rec_count = 2; >>> + } >>> + else if((insn_bits24_27 & 0x0e) == 0x06) >>> + { >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; >>> + if (bits (aarch64_insn_r->aarch64_insn, 21, 22) == 0x01) >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; >>> + } >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + } >>> + else if ((insn_bits28_31 & 0x07) == 0x01 && (insn_bits24_27 & 0x0c) == 0x04) >>> + { >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; >>> + if (bit (aarch64_insn_r->aarch64_insn, 31)) >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; >>> + } >>> + else >>> + /* All other types of branch instructions. */ >>> + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; >>> + >>> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >>> + record_buf); >>> + return AARCH64_RECORD_SUCCESS; >>> +} >>> + >>> +/* Record handler for load and store instructions. */ >>> +static unsigned int >>> +aarch64_record_load_store (insn_decode_record *aarch64_insn_r) >>> +{ >>> + uint8_t insn_bits24_27, insn_bits28_29, insn_bits10_11; >>> + uint8_t insn_bit23, insn_bit21; >>> + uint8_t opc, size_bits, ld_flag, vector_flag; >>> + uint32_t reg_rn, reg_rt, reg_rt2; >>> + uint64_t datasize, offset; >>> + uint32_t record_buf[8]; >>> + uint64_t record_buf_mem[8]; >>> + CORE_ADDR address; >>> + >>> + insn_bits10_11 = bits (aarch64_insn_r->aarch64_insn, 10, 11); >>> + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); >>> + insn_bits28_29 = bits (aarch64_insn_r->aarch64_insn, 28, 29); >>> + insn_bit21 = bit (aarch64_insn_r->aarch64_insn, 21); >>> + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); >>> + ld_flag = bit (aarch64_insn_r->aarch64_insn, 22); >>> + vector_flag = bit (aarch64_insn_r->aarch64_insn, 26); >>> + reg_rt = bits (aarch64_insn_r->aarch64_insn, 0, 4); >>> + reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); >>> + reg_rt2 = bits (aarch64_insn_r->aarch64_insn, 10, 14); >>> + size_bits = bits (aarch64_insn_r->aarch64_insn, 30, 31); >>> + >>> + /* Load/store exclusive instructions decoding. */ >>> + if (insn_bits24_27 == 0x08 && insn_bits28_29 == 0x00) >>> + { >>> + if (ld_flag) >>> + { >>> + record_buf[0] = reg_rt; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + if (insn_bit21) >>> + { >>> + record_buf[1] = reg_rt2; >>> + aarch64_insn_r->reg_rec_count = 2; >>> + } >>> + } >>> + else >>> + { >>> + if (insn_bit21) >>> + datasize = (8 << size_bits) * 2; >>> + else >>> + datasize = (8 << size_bits); >>> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >>> + &address); >>> + record_buf_mem[0] = datasize / 8; >>> + record_buf_mem[1] = address; >>> + aarch64_insn_r->mem_rec_count = 1; >>> + if (!insn_bit23) >>> + { >>> + /* Save register rs. */ >>> + record_buf[0] = bits (aarch64_insn_r->aarch64_insn, 16, 20); >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + } >>> + } >>> + /* Load register (literal) instructions decoding. */ >>> + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x01) >>> + { >>> + if (vector_flag) >>> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >>> + else >>> + record_buf[0] = reg_rt; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + /* All types of load/store pair instructions decoding. */ >>> + else if ((insn_bits24_27 & 0x0a) == 0x08 && insn_bits28_29 == 0x02) >>> + { >>> + if (ld_flag) >>> + { >>> + if (vector_flag) >>> + { >>> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >>> + record_buf[1] = reg_rt2 + AARCH64_V0_REGNUM; >>> + } >>> + else >>> + { >>> + record_buf[0] = reg_rt; >>> + record_buf[1] = reg_rt2; >>> + } >>> + aarch64_insn_r->reg_rec_count = 2; >>> + } >>> + else >>> + { >>> + uint16_t imm7_off; >>> + imm7_off = bits (aarch64_insn_r->aarch64_insn, 15, 21); >>> + if (!vector_flag) >>> + size_bits = size_bits >> 1; >>> + datasize = 8 << (2 + size_bits); >>> + offset = (imm7_off & 0x40) ? (~imm7_off & 0x007f) + 1 : imm7_off; >>> + offset = offset << (2 + size_bits); >>> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >>> + &address); >>> + if (!((insn_bits24_27 & 0x0b) == 0x08 && insn_bit23)) >>> + { >>> + if (imm7_off & 0x40) >>> + address = address - offset; >>> + else >>> + address = address + offset; >>> + } >>> + >>> + record_buf_mem[0] = datasize / 8; >>> + record_buf_mem[1] = address; >>> + record_buf_mem[2] = datasize / 8; >>> + record_buf_mem[3] = address + (datasize / 8); >>> + aarch64_insn_r->mem_rec_count = 2; >>> + } >>> + if (bit (aarch64_insn_r->aarch64_insn, 23)) >>> + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; >>> + } >>> + /* Load/store register (unsigned immediate) instructions. */ >>> + else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x03) >>> + { >>> + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); >>> + if (!(opc >> 1)) >>> + if (opc & 0x01) >>> + ld_flag = 0x01; >>> + else >>> + ld_flag = 0x0; >>> + else >>> + if (size_bits != 0x03) >>> + ld_flag = 0x01; >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + >>> + if (!ld_flag) >>> + { >>> + offset = bits (aarch64_insn_r->aarch64_insn, 10, 21); >>> + datasize = 8 << size_bits; >>> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >>> + &address); >>> + offset = offset << size_bits; >>> + address = address + offset; >>> + >>> + record_buf_mem[0] = datasize >> 3; >>> + record_buf_mem[1] = address; >>> + aarch64_insn_r->mem_rec_count = 1; >>> + } >>> + else >>> + { >>> + if (vector_flag) >>> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >>> + else >>> + record_buf[0] = reg_rt; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + } >>> + /* Load/store register (register offset) instructions. */ >>> + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && >>> + insn_bits10_11 == 0x02 && insn_bit21) >>> + { >>> + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); >>> + if (!(opc >> 1)) >>> + if (opc & 0x01) >>> + ld_flag = 0x01; >>> + else >>> + ld_flag = 0x0; >>> + else >>> + if (size_bits != 0x03) >>> + ld_flag = 0x01; >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + >>> + if (!ld_flag) >>> + { >>> + uint64_t reg_rm_val; >>> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, >>> + bits (aarch64_insn_r->aarch64_insn, 16, 20), ®_rm_val); >>> + if (bit (aarch64_insn_r->aarch64_insn, 12)) >>> + offset = reg_rm_val << size_bits; >>> + else >>> + offset = reg_rm_val; >>> + datasize = 8 << size_bits; >>> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >>> + &address); >>> + address = address + offset; >>> + record_buf_mem[0] = datasize >> 3; >>> + record_buf_mem[1] = address; >>> + aarch64_insn_r->mem_rec_count = 1; >>> + } >>> + else >>> + { >>> + if (vector_flag) >>> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >>> + else >>> + record_buf[0] = reg_rt; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + } >>> + /* Load/store register (immediate) instructions. */ >>> + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && >>> + !insn_bit21) >>> + { >>> + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); >>> + if (!(opc >> 1)) >>> + if (opc & 0x01) >>> + ld_flag = 0x01; >>> + else >>> + ld_flag = 0x0; >>> + else >>> + if (size_bits != 0x03) >>> + ld_flag = 0x01; >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + >>> + if (!ld_flag) >>> + { >>> + uint16_t imm9_off; >>> + imm9_off = bits (aarch64_insn_r->aarch64_insn, 12, 20); >>> + offset = (imm9_off & 0x0100) ? (((~imm9_off) & 0x01ff) + 1) : imm9_off; >>> + datasize = 8 << size_bits; >>> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, >>> + &address); >>> + if (insn_bits10_11 != 0x01) >>> + { >>> + if (imm9_off & 0x0100) >>> + address = address - offset; >>> + else >>> + address = address + offset; >>> + } >>> + record_buf_mem[0] = datasize >> 3; >>> + record_buf_mem[1] = address; >>> + aarch64_insn_r->mem_rec_count = 1; >>> + } >>> + else >>> + { >>> + if (vector_flag) >>> + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; >>> + else >>> + record_buf[0] = reg_rt; >>> + aarch64_insn_r->reg_rec_count = 1; >>> + } >>> + if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03) >>> + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; >>> + } >>> + /* Advanced SIMD load/store instructions. */ >>> + else >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + >>> + MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count, >>> + record_buf_mem); >>> + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, >>> + record_buf); >>> + return AARCH64_RECORD_SUCCESS; >>> +} >>> +/* Decodes insns type and invokes its record handler. */ >>> + >>> +static unsigned int >>> +aarch64_record_decode_insn_handler (insn_decode_record *aarch64_insn_r) >>> +{ >>> + uint32_t ins_bit25, ins_bit26, ins_bit27, ins_bit28; >>> + >>> + ins_bit25 = bit (aarch64_insn_r->aarch64_insn, 25); >>> + ins_bit26 = bit (aarch64_insn_r->aarch64_insn, 26); >>> + ins_bit27 = bit (aarch64_insn_r->aarch64_insn, 27); >>> + ins_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); >>> + >>> + /* Data processing - immediate instructions. */ >>> + if (!ins_bit26 && !ins_bit27 && ins_bit28) >>> + return aarch64_record_data_proc_imm (aarch64_insn_r); >>> + >>> + /* Branch, exception generation and system instructions. */ >>> + if (ins_bit26 && !ins_bit27 && ins_bit28) >>> + return aarch64_record_branch_except_sys (aarch64_insn_r); >>> + >>> + /* Load and store instructions. */ >>> + if (!ins_bit25 && ins_bit27) >>> + return aarch64_record_load_store (aarch64_insn_r); >>> + >>> + /* Data processing - register instructions. */ >>> + if (ins_bit25 && !ins_bit26 && ins_bit27) >>> + return aarch64_record_data_proc_reg (aarch64_insn_r); >>> + >>> + /* Data processing - SIMD and floating point instructions. */ >>> + if (ins_bit25 && ins_bit26 && ins_bit27) >>> + return AARCH64_RECORD_UNSUPPORTED; >>> + >>> + return AARCH64_RECORD_UNSUPPORTED; >>> +} >>> + >>> +/* Cleans up local record registers and memory allocations. */ >>> + >>> +static void >>> +deallocate_reg_mem (insn_decode_record *record) >>> +{ >>> + xfree (record->aarch64_regs); >>> + xfree (record->aarch64_mems); >>> +} >>> + >>> +/* Parse the current instruction and record the values of the registers and >>> + memory that will be changed in current instruction to record_arch_list >>> + return -1 if something is wrong. */ >>> + >>> +int >>> +aarch64_process_record (struct gdbarch *gdbarch, struct regcache *regcache, >>> + CORE_ADDR insn_addr) >>> +{ >>> + uint32_t rec_no = 0; >>> + uint8_t insn_size = 4; >>> + uint32_t ret = 0; >>> + ULONGEST t_bit = 0, insn_id = 0; >>> + gdb_byte buf[insn_size]; >>> + insn_decode_record aarch64_record; >>> + >>> + memset (&buf[0], 0, insn_size); >>> + memset (&aarch64_record, 0, sizeof (insn_decode_record)); >>> + target_read_memory (insn_addr, &buf[0], insn_size); >>> + aarch64_record.aarch64_insn = (uint32_t) extract_unsigned_integer (&buf[0], >>> + insn_size, gdbarch_byte_order (gdbarch)); >>> + aarch64_record.regcache = regcache; >>> + aarch64_record.this_addr = insn_addr; >>> + aarch64_record.gdbarch = gdbarch; >>> + >>> + ret = aarch64_record_decode_insn_handler (&aarch64_record); >>> + if (ret == AARCH64_RECORD_UNSUPPORTED) >>> + { >>> + printf_unfiltered (_("Process record does not support instruction " >>> + "0x%0x at address %s.\n"),aarch64_record.aarch64_insn, >>> + paddress (gdbarch, insn_addr)); >>> + ret = -1; >>> + } >>> + >>> + if (0 == ret) >>> + { >>> + /* Record registers. */ >>> + record_full_arch_list_add_reg (aarch64_record.regcache, AARCH64_PC_REGNUM); >>> + if (aarch64_record.aarch64_regs) >>> + for (rec_no = 0; rec_no < aarch64_record.reg_rec_count; rec_no++) >>> + if (record_full_arch_list_add_reg (aarch64_record.regcache, >>> + aarch64_record.aarch64_regs[rec_no])) >>> + ret = -1; >>> + >>> + /* Record memories. */ >>> + if (aarch64_record.aarch64_mems) >>> + for (rec_no = 0; rec_no < aarch64_record.mem_rec_count; rec_no++) >>> + if (record_full_arch_list_add_mem >>> + ((CORE_ADDR)aarch64_record.aarch64_mems[rec_no].addr, >>> + aarch64_record.aarch64_mems[rec_no].len)) >>> + ret = -1; >>> + >>> + if (record_full_arch_list_add_end ()) >>> + ret = -1; >>> + } >>> + >>> + deallocate_reg_mem (&aarch64_record); >>> + return ret; >>> +} >>> diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h >>> index 78fb779..3dd3dcc 100644 >>> --- a/gdb/aarch64-tdep.h >>> +++ b/gdb/aarch64-tdep.h >>> @@ -90,4 +90,7 @@ struct gdbarch_tdep >>> struct type *vnb_type; >>> }; >>> >>> +extern int aarch64_process_record (struct gdbarch *gdbarch, >>> + struct regcache *regcache, CORE_ADDR addr); >>> + >>> #endif /* aarch64-tdep.h */ >>> -- >>> 1.9.1 >>> >> >> Ping! Kindly help me approve this patch series. > > ping! > ping!
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index e5565a8..5ab7b37 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -401,6 +401,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand); set_gdbarch_stap_parse_special_token (gdbarch, aarch64_stap_parse_special_token); + + /* Reversible debugging, process record. */ + set_gdbarch_process_record (gdbarch, aarch64_process_record); } /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 1898f6b..ed28f68 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -50,6 +50,9 @@ #include "vec.h" +#include "record.h" +#include "record-full.h" + #include "features/aarch64.c" /* Pseudo register base numbers. */ @@ -2804,3 +2807,578 @@ When on, AArch64 specific debugging is enabled."), show_aarch64_debug, &setdebuglist, &showdebuglist); } + +/* AArch64 process record-replay related structures, defines etc. */ + +#define submask(x) ((1L << ((x) + 1)) - 1) +#define bit(obj,st) (((obj) >> (st)) & 1) +#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st))) + +#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \ + do \ + { \ + unsigned int reg_len = LENGTH; \ + if (reg_len) \ + { \ + REGS = XNEWVEC (uint32_t, reg_len); \ + memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \ + } \ + } \ + while (0) + +#define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \ + do \ + { \ + unsigned int mem_len = LENGTH; \ + if (mem_len) \ + { \ + MEMS = XNEWVEC (struct aarch64_mem_r, mem_len); \ + memcpy(&MEMS->len, &RECORD_BUF[0], \ + sizeof(struct aarch64_mem_r) * LENGTH); \ + } \ + } \ + while (0) + +/* AArch64 memory record structure. */ +struct aarch64_mem_r +{ + uint64_t len; /* Record length. */ + uint64_t addr; /* Memory address. */ +}; + +enum aarch64_record_result +{ + AARCH64_RECORD_SUCCESS, + AARCH64_RECORD_FAILURE, + AARCH64_RECORD_UNSUPPORTED +}; + +/* AArch64 instruction record contains opcode of current insn and execution + state (before entry to decode_insn()), contains list of to-be-modified + registers and memory blocks (on return from decode_insn()). */ + +typedef struct insn_decode_record_t +{ + struct gdbarch *gdbarch; + struct regcache *regcache; + CORE_ADDR this_addr; + uint32_t aarch64_insn; + uint32_t mem_rec_count; + uint32_t reg_rec_count; + uint32_t *aarch64_regs; + struct aarch64_mem_r *aarch64_mems; +} insn_decode_record; + +/* Record handler for data processing - register instructions. */ +static unsigned int +aarch64_record_data_proc_reg (insn_decode_record *aarch64_insn_r) +{ + uint8_t reg_rd, insn_bits24_27, insn_bits21_23, setflags; + uint32_t record_buf[4]; + + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); + insn_bits21_23 = bits (aarch64_insn_r->aarch64_insn, 21, 23); + + if (!bit (aarch64_insn_r->aarch64_insn, 28)) + { + /* Logical (shifted register). */ + if (insn_bits24_27 == 0x0a) + setflags = (bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03); + /* Add/subtract. */ + else if (insn_bits24_27 == 0x0b) + setflags = bit (aarch64_insn_r->aarch64_insn, 29); + else + return AARCH64_RECORD_UNSUPPORTED; + + record_buf[0] = reg_rd; + aarch64_insn_r->reg_rec_count = 1; + if (setflags) + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; + } + else + { + if (insn_bits24_27 == 0x0b) + { + /* Data-processing (3 source). */ + record_buf[0] = reg_rd; + aarch64_insn_r->reg_rec_count = 1; + } + else if (insn_bits24_27 == 0x0a) + { + if (insn_bits21_23 == 0x00) + { + /* Add/subtract (with carry). */ + record_buf[0] = reg_rd; + aarch64_insn_r->reg_rec_count = 1; + if (bit (aarch64_insn_r->aarch64_insn, 29)) + { + record_buf[1] = AARCH64_CPSR_REGNUM; + aarch64_insn_r->reg_rec_count = 2; + } + } + else if (insn_bits21_23 == 0x02) + { + /* Conditional compare (register) / Conditional compare (immediate). */ + record_buf[0] = AARCH64_CPSR_REGNUM; + aarch64_insn_r->reg_rec_count = 1; + } + else if (insn_bits21_23 == 0x04 || insn_bits21_23 == 0x06) + { + /* CConditional select. */ + /* Data-processing (2 source). */ + /* Data-processing (1 source). */ + record_buf[0] = reg_rd; + aarch64_insn_r->reg_rec_count = 1; + } + else + return AARCH64_RECORD_UNSUPPORTED; + } + } + + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, + record_buf); + return AARCH64_RECORD_SUCCESS; +} + +/* Record handler for data processing - immediate instructions. */ +static unsigned int +aarch64_record_data_proc_imm (insn_decode_record *aarch64_insn_r) +{ + uint8_t reg_rd, insn_bit28, insn_bit23, insn_bits24_27, setflags; + uint32_t record_buf[4]; + + reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); + insn_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); + + /* PC rel addressing / Move wide immediate / BitField / Extract. */ + if (insn_bits24_27 == 0x00 || insn_bits24_27 == 0x03 || + (insn_bits24_27 == 0x02 && insn_bit23)) + { + record_buf[0] = reg_rd; + aarch64_insn_r->reg_rec_count = 1; + } + else if (insn_bits24_27 == 0x01) + { + /* Add/Subtract (immediate). */ + setflags = bit (aarch64_insn_r->aarch64_insn, 29); + record_buf[0] = reg_rd; + aarch64_insn_r->reg_rec_count = 1; + if (setflags) + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; + } + else if (insn_bits24_27 == 0x02 && !insn_bit23) + { + /* Logical (immediate). */ + setflags = bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03; + record_buf[0] = reg_rd; + aarch64_insn_r->reg_rec_count = 1; + if (setflags) + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM; + } + else + return AARCH64_RECORD_UNSUPPORTED; + + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, + record_buf); + return AARCH64_RECORD_SUCCESS; +} + +/* Record handler for branch, exception generation and system instructions. */ +static unsigned int +aarch64_record_branch_except_sys (insn_decode_record *aarch64_insn_r) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (aarch64_insn_r->gdbarch); + uint8_t insn_bits24_27, insn_bits28_31, insn_bits22_23; + uint32_t record_buf[4]; + + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); + insn_bits28_31 = bits (aarch64_insn_r->aarch64_insn, 28, 31); + insn_bits22_23 = bits (aarch64_insn_r->aarch64_insn, 22, 23); + + if (insn_bits28_31 == 0x0d) + { + /* Exception generation instructions. */ + if (insn_bits24_27 == 0x04) + return AARCH64_RECORD_UNSUPPORTED; + /* System instructions. */ + else if (insn_bits24_27 == 0x05 && insn_bits22_23 == 0x00) + { + record_buf[0] = AARCH64_CPSR_REGNUM; + record_buf[1] = bits (aarch64_insn_r->aarch64_insn, 0, 4); + aarch64_insn_r->reg_rec_count = 2; + } + else if((insn_bits24_27 & 0x0e) == 0x06) + { + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; + if (bits (aarch64_insn_r->aarch64_insn, 21, 22) == 0x01) + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; + } + else + return AARCH64_RECORD_UNSUPPORTED; + } + else if ((insn_bits28_31 & 0x07) == 0x01 && (insn_bits24_27 & 0x0c) == 0x04) + { + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; + if (bit (aarch64_insn_r->aarch64_insn, 31)) + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM; + } + else + /* All other types of branch instructions. */ + record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM; + + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, + record_buf); + return AARCH64_RECORD_SUCCESS; +} + +/* Record handler for load and store instructions. */ +static unsigned int +aarch64_record_load_store (insn_decode_record *aarch64_insn_r) +{ + uint8_t insn_bits24_27, insn_bits28_29, insn_bits10_11; + uint8_t insn_bit23, insn_bit21; + uint8_t opc, size_bits, ld_flag, vector_flag; + uint32_t reg_rn, reg_rt, reg_rt2; + uint64_t datasize, offset; + uint32_t record_buf[8]; + uint64_t record_buf_mem[8]; + CORE_ADDR address; + + insn_bits10_11 = bits (aarch64_insn_r->aarch64_insn, 10, 11); + insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27); + insn_bits28_29 = bits (aarch64_insn_r->aarch64_insn, 28, 29); + insn_bit21 = bit (aarch64_insn_r->aarch64_insn, 21); + insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23); + ld_flag = bit (aarch64_insn_r->aarch64_insn, 22); + vector_flag = bit (aarch64_insn_r->aarch64_insn, 26); + reg_rt = bits (aarch64_insn_r->aarch64_insn, 0, 4); + reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); + reg_rt2 = bits (aarch64_insn_r->aarch64_insn, 10, 14); + size_bits = bits (aarch64_insn_r->aarch64_insn, 30, 31); + + /* Load/store exclusive instructions decoding. */ + if (insn_bits24_27 == 0x08 && insn_bits28_29 == 0x00) + { + if (ld_flag) + { + record_buf[0] = reg_rt; + aarch64_insn_r->reg_rec_count = 1; + if (insn_bit21) + { + record_buf[1] = reg_rt2; + aarch64_insn_r->reg_rec_count = 2; + } + } + else + { + if (insn_bit21) + datasize = (8 << size_bits) * 2; + else + datasize = (8 << size_bits); + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, + &address); + record_buf_mem[0] = datasize / 8; + record_buf_mem[1] = address; + aarch64_insn_r->mem_rec_count = 1; + if (!insn_bit23) + { + /* Save register rs. */ + record_buf[0] = bits (aarch64_insn_r->aarch64_insn, 16, 20); + aarch64_insn_r->reg_rec_count = 1; + } + } + } + /* Load register (literal) instructions decoding. */ + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x01) + { + if (vector_flag) + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; + else + record_buf[0] = reg_rt; + aarch64_insn_r->reg_rec_count = 1; + } + /* All types of load/store pair instructions decoding. */ + else if ((insn_bits24_27 & 0x0a) == 0x08 && insn_bits28_29 == 0x02) + { + if (ld_flag) + { + if (vector_flag) + { + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; + record_buf[1] = reg_rt2 + AARCH64_V0_REGNUM; + } + else + { + record_buf[0] = reg_rt; + record_buf[1] = reg_rt2; + } + aarch64_insn_r->reg_rec_count = 2; + } + else + { + uint16_t imm7_off; + imm7_off = bits (aarch64_insn_r->aarch64_insn, 15, 21); + if (!vector_flag) + size_bits = size_bits >> 1; + datasize = 8 << (2 + size_bits); + offset = (imm7_off & 0x40) ? (~imm7_off & 0x007f) + 1 : imm7_off; + offset = offset << (2 + size_bits); + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, + &address); + if (!((insn_bits24_27 & 0x0b) == 0x08 && insn_bit23)) + { + if (imm7_off & 0x40) + address = address - offset; + else + address = address + offset; + } + + record_buf_mem[0] = datasize / 8; + record_buf_mem[1] = address; + record_buf_mem[2] = datasize / 8; + record_buf_mem[3] = address + (datasize / 8); + aarch64_insn_r->mem_rec_count = 2; + } + if (bit (aarch64_insn_r->aarch64_insn, 23)) + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; + } + /* Load/store register (unsigned immediate) instructions. */ + else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x03) + { + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); + if (!(opc >> 1)) + if (opc & 0x01) + ld_flag = 0x01; + else + ld_flag = 0x0; + else + if (size_bits != 0x03) + ld_flag = 0x01; + else + return AARCH64_RECORD_UNSUPPORTED; + + if (!ld_flag) + { + offset = bits (aarch64_insn_r->aarch64_insn, 10, 21); + datasize = 8 << size_bits; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, + &address); + offset = offset << size_bits; + address = address + offset; + + record_buf_mem[0] = datasize >> 3; + record_buf_mem[1] = address; + aarch64_insn_r->mem_rec_count = 1; + } + else + { + if (vector_flag) + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; + else + record_buf[0] = reg_rt; + aarch64_insn_r->reg_rec_count = 1; + } + } + /* Load/store register (register offset) instructions. */ + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && + insn_bits10_11 == 0x02 && insn_bit21) + { + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); + if (!(opc >> 1)) + if (opc & 0x01) + ld_flag = 0x01; + else + ld_flag = 0x0; + else + if (size_bits != 0x03) + ld_flag = 0x01; + else + return AARCH64_RECORD_UNSUPPORTED; + + if (!ld_flag) + { + uint64_t reg_rm_val; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, + bits (aarch64_insn_r->aarch64_insn, 16, 20), ®_rm_val); + if (bit (aarch64_insn_r->aarch64_insn, 12)) + offset = reg_rm_val << size_bits; + else + offset = reg_rm_val; + datasize = 8 << size_bits; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, + &address); + address = address + offset; + record_buf_mem[0] = datasize >> 3; + record_buf_mem[1] = address; + aarch64_insn_r->mem_rec_count = 1; + } + else + { + if (vector_flag) + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; + else + record_buf[0] = reg_rt; + aarch64_insn_r->reg_rec_count = 1; + } + } + /* Load/store register (immediate) instructions. */ + else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03 && + !insn_bit21) + { + opc = bits (aarch64_insn_r->aarch64_insn, 22, 23); + if (!(opc >> 1)) + if (opc & 0x01) + ld_flag = 0x01; + else + ld_flag = 0x0; + else + if (size_bits != 0x03) + ld_flag = 0x01; + else + return AARCH64_RECORD_UNSUPPORTED; + + if (!ld_flag) + { + uint16_t imm9_off; + imm9_off = bits (aarch64_insn_r->aarch64_insn, 12, 20); + offset = (imm9_off & 0x0100) ? (((~imm9_off) & 0x01ff) + 1) : imm9_off; + datasize = 8 << size_bits; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, + &address); + if (insn_bits10_11 != 0x01) + { + if (imm9_off & 0x0100) + address = address - offset; + else + address = address + offset; + } + record_buf_mem[0] = datasize >> 3; + record_buf_mem[1] = address; + aarch64_insn_r->mem_rec_count = 1; + } + else + { + if (vector_flag) + record_buf[0] = reg_rt + AARCH64_V0_REGNUM; + else + record_buf[0] = reg_rt; + aarch64_insn_r->reg_rec_count = 1; + } + if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03) + record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; + } + /* Advanced SIMD load/store instructions. */ + else + return AARCH64_RECORD_UNSUPPORTED; + + MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count, + record_buf_mem); + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, + record_buf); + return AARCH64_RECORD_SUCCESS; +} +/* Decodes insns type and invokes its record handler. */ + +static unsigned int +aarch64_record_decode_insn_handler (insn_decode_record *aarch64_insn_r) +{ + uint32_t ins_bit25, ins_bit26, ins_bit27, ins_bit28; + + ins_bit25 = bit (aarch64_insn_r->aarch64_insn, 25); + ins_bit26 = bit (aarch64_insn_r->aarch64_insn, 26); + ins_bit27 = bit (aarch64_insn_r->aarch64_insn, 27); + ins_bit28 = bit (aarch64_insn_r->aarch64_insn, 28); + + /* Data processing - immediate instructions. */ + if (!ins_bit26 && !ins_bit27 && ins_bit28) + return aarch64_record_data_proc_imm (aarch64_insn_r); + + /* Branch, exception generation and system instructions. */ + if (ins_bit26 && !ins_bit27 && ins_bit28) + return aarch64_record_branch_except_sys (aarch64_insn_r); + + /* Load and store instructions. */ + if (!ins_bit25 && ins_bit27) + return aarch64_record_load_store (aarch64_insn_r); + + /* Data processing - register instructions. */ + if (ins_bit25 && !ins_bit26 && ins_bit27) + return aarch64_record_data_proc_reg (aarch64_insn_r); + + /* Data processing - SIMD and floating point instructions. */ + if (ins_bit25 && ins_bit26 && ins_bit27) + return AARCH64_RECORD_UNSUPPORTED; + + return AARCH64_RECORD_UNSUPPORTED; +} + +/* Cleans up local record registers and memory allocations. */ + +static void +deallocate_reg_mem (insn_decode_record *record) +{ + xfree (record->aarch64_regs); + xfree (record->aarch64_mems); +} + +/* Parse the current instruction and record the values of the registers and + memory that will be changed in current instruction to record_arch_list + return -1 if something is wrong. */ + +int +aarch64_process_record (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR insn_addr) +{ + uint32_t rec_no = 0; + uint8_t insn_size = 4; + uint32_t ret = 0; + ULONGEST t_bit = 0, insn_id = 0; + gdb_byte buf[insn_size]; + insn_decode_record aarch64_record; + + memset (&buf[0], 0, insn_size); + memset (&aarch64_record, 0, sizeof (insn_decode_record)); + target_read_memory (insn_addr, &buf[0], insn_size); + aarch64_record.aarch64_insn = (uint32_t) extract_unsigned_integer (&buf[0], + insn_size, gdbarch_byte_order (gdbarch)); + aarch64_record.regcache = regcache; + aarch64_record.this_addr = insn_addr; + aarch64_record.gdbarch = gdbarch; + + ret = aarch64_record_decode_insn_handler (&aarch64_record); + if (ret == AARCH64_RECORD_UNSUPPORTED) + { + printf_unfiltered (_("Process record does not support instruction " + "0x%0x at address %s.\n"),aarch64_record.aarch64_insn, + paddress (gdbarch, insn_addr)); + ret = -1; + } + + if (0 == ret) + { + /* Record registers. */ + record_full_arch_list_add_reg (aarch64_record.regcache, AARCH64_PC_REGNUM); + if (aarch64_record.aarch64_regs) + for (rec_no = 0; rec_no < aarch64_record.reg_rec_count; rec_no++) + if (record_full_arch_list_add_reg (aarch64_record.regcache, + aarch64_record.aarch64_regs[rec_no])) + ret = -1; + + /* Record memories. */ + if (aarch64_record.aarch64_mems) + for (rec_no = 0; rec_no < aarch64_record.mem_rec_count; rec_no++) + if (record_full_arch_list_add_mem + ((CORE_ADDR)aarch64_record.aarch64_mems[rec_no].addr, + aarch64_record.aarch64_mems[rec_no].len)) + ret = -1; + + if (record_full_arch_list_add_end ()) + ret = -1; + } + + deallocate_reg_mem (&aarch64_record); + return ret; +} diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index 78fb779..3dd3dcc 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -90,4 +90,7 @@ struct gdbarch_tdep struct type *vnb_type; }; +extern int aarch64_process_record (struct gdbarch *gdbarch, + struct regcache *regcache, CORE_ADDR addr); + #endif /* aarch64-tdep.h */