Message ID | 20240510052408.2173579-3-thiago.bauermann@linaro.org |
---|---|
State | New |
Headers | show |
Series | Add support for AArch64 MOPS instructions | expand |
Hi, Just a minor suggestion. Otherwise the patch looks OK. On 5/10/24 06:24, Thiago Jung Bauermann wrote: > There are two kinds of MOPS instructions: set instructions and copy > instructions. Within each group there are variants with minor > differences in how they read or write to memory — e.g., non-temporal > read and/or write, unprivileged read and/or write and permutations of > those — but they work in the same way in terms of the registers and > regions of memory that they modify. > > PR tdep/31666 > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31666 > --- > gdb/aarch64-tdep.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 84 insertions(+) > > No change since v1. > > diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c > index 05ecd421cd0e..a9a67107675c 100644 > --- a/gdb/aarch64-tdep.c > +++ b/gdb/aarch64-tdep.c > @@ -5188,6 +5188,86 @@ aarch64_record_asimd_load_store (aarch64_insn_decode_record *aarch64_insn_r) > return AARCH64_RECORD_SUCCESS; > } > > +/* Record handler for Memory Copy and Memory Set instructions. */ > + > +static unsigned int > +aarch64_record_memcopy_memset (aarch64_insn_decode_record *aarch64_insn_r) > +{ > + if (record_debug) > + debug_printf ("Process record: memory copy and memory set\n"); > + > + uint8_t op1 = bits (aarch64_insn_r->aarch64_insn, 22, 23); > + uint8_t op2 = bits (aarch64_insn_r->aarch64_insn, 12, 15); > + uint32_t reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); > + uint32_t reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); > + uint32_t record_buf[3]; > + uint64_t record_buf_mem[4]; > + > + if (op1 != 3) > + { > + /* Copy instructions. */ > + uint32_t reg_rs = bits (aarch64_insn_r->aarch64_insn, 16, 20); > + > + record_buf[0] = reg_rd; > + record_buf[1] = reg_rn; > + record_buf[2] = reg_rs; > + aarch64_insn_r->reg_rec_count = 3; > + > + ULONGEST dest_addr; > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, > + &dest_addr); > + ULONGEST source_addr; > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rs, > + &source_addr); > + LONGEST length; > + regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, > + &length); > + > + /* In a processor using algorithm option A, the length in Rn has an > + inverted sign. */ > + if (length < 0) > + length *= -1; > + > + record_buf_mem[0] = length; > + record_buf_mem[1] = dest_addr; > + record_buf_mem[2] = length; > + record_buf_mem[3] = source_addr; > + aarch64_insn_r->mem_rec_count = 2; > + } > + else if ((op1 == 3 && op2 < 12) || (op1 == 3 && op2 < 12)) > + { > + /* Set instructions. */ > + record_buf[0] = reg_rd; > + record_buf[1] = reg_rn; > + aarch64_insn_r->reg_rec_count = 2; > + > + ULONGEST address; > + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, > + &address); > + > + LONGEST length; > + regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, > + &length); > + > + /* In a processor using algorithm option B, the length in Rn has an > + inverted sign. */ > + if (length < 0) > + length *= -1; > + > + record_buf_mem[0] = length; > + record_buf_mem[1] = address; > + aarch64_insn_r->mem_rec_count = 1; > + } Looks like both cases above could potentially share some code in a common path. Would be nice to do so if it doesn't make the code all awkward. If it does, then this is fine. > + else > + return AARCH64_RECORD_UNKNOWN; > + > + 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; > +} > + > /* Record handler for load and store instructions. */ > > static unsigned int > @@ -5465,6 +5545,10 @@ aarch64_record_load_store (aarch64_insn_decode_record *aarch64_insn_r) > if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03) > record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; > } > + /* Memory Copy and Memory Set instructions. */ > + else if ((insn_bits24_27 & 1) == 1 && insn_bits28_29 == 1 > + && insn_bits10_11 == 1 && !insn_bit21) > + return aarch64_record_memcopy_memset (aarch64_insn_r); > /* Advanced SIMD load/store instructions. */ > else > return aarch64_record_asimd_load_store (aarch64_insn_r);
Hello Luis, Luis Machado <luis.machado@arm.com> writes: > Just a minor suggestion. Otherwise the patch looks OK. Great, thanks! > On 5/10/24 06:24, Thiago Jung Bauermann wrote: >> +static unsigned int >> +aarch64_record_memcopy_memset (aarch64_insn_decode_record *aarch64_insn_r) >> +{ >> + if (record_debug) >> + debug_printf ("Process record: memory copy and memory set\n"); >> + >> + uint8_t op1 = bits (aarch64_insn_r->aarch64_insn, 22, 23); >> + uint8_t op2 = bits (aarch64_insn_r->aarch64_insn, 12, 15); >> + uint32_t reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); >> + uint32_t reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); >> + uint32_t record_buf[3]; >> + uint64_t record_buf_mem[4]; >> + >> + if (op1 != 3) >> + { >> + /* Copy instructions. */ >> + uint32_t reg_rs = bits (aarch64_insn_r->aarch64_insn, 16, 20); >> + >> + record_buf[0] = reg_rd; >> + record_buf[1] = reg_rn; >> + record_buf[2] = reg_rs; >> + aarch64_insn_r->reg_rec_count = 3; >> + >> + ULONGEST dest_addr; >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, >> + &dest_addr); >> + ULONGEST source_addr; >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rs, >> + &source_addr); >> + LONGEST length; >> + regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, >> + &length); >> + >> + /* In a processor using algorithm option A, the length in Rn has an >> + inverted sign. */ >> + if (length < 0) >> + length *= -1; >> + >> + record_buf_mem[0] = length; >> + record_buf_mem[1] = dest_addr; >> + record_buf_mem[2] = length; >> + record_buf_mem[3] = source_addr; >> + aarch64_insn_r->mem_rec_count = 2; >> + } >> + else if ((op1 == 3 && op2 < 12) || (op1 == 3 && op2 < 12)) The or operands are identical. Fixed in v4. >> + { >> + /* Set instructions. */ >> + record_buf[0] = reg_rd; >> + record_buf[1] = reg_rn; >> + aarch64_insn_r->reg_rec_count = 2; >> + >> + ULONGEST address; >> + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, >> + &address); >> + >> + LONGEST length; >> + regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, >> + &length); >> + >> + /* In a processor using algorithm option B, the length in Rn has an >> + inverted sign. */ >> + if (length < 0) >> + length *= -1; >> + >> + record_buf_mem[0] = length; >> + record_buf_mem[1] = address; >> + aarch64_insn_r->mem_rec_count = 1; >> + } > > Looks like both cases above could potentially share some code in a common path. Would be > nice > to do so if it doesn't make the code all awkward. If it does, then this is fine. Well spotted. It turns out that for the copy instructions we need to record the same information as for the set instructions, plus an additional register and memory region. Using a common path improves the function. Thanks for the suggestion. Fixed in v4. >> + else >> + return AARCH64_RECORD_UNKNOWN; >> + >> + 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; >> +}
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 05ecd421cd0e..a9a67107675c 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -5188,6 +5188,86 @@ aarch64_record_asimd_load_store (aarch64_insn_decode_record *aarch64_insn_r) return AARCH64_RECORD_SUCCESS; } +/* Record handler for Memory Copy and Memory Set instructions. */ + +static unsigned int +aarch64_record_memcopy_memset (aarch64_insn_decode_record *aarch64_insn_r) +{ + if (record_debug) + debug_printf ("Process record: memory copy and memory set\n"); + + uint8_t op1 = bits (aarch64_insn_r->aarch64_insn, 22, 23); + uint8_t op2 = bits (aarch64_insn_r->aarch64_insn, 12, 15); + uint32_t reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); + uint32_t reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); + uint32_t record_buf[3]; + uint64_t record_buf_mem[4]; + + if (op1 != 3) + { + /* Copy instructions. */ + uint32_t reg_rs = bits (aarch64_insn_r->aarch64_insn, 16, 20); + + record_buf[0] = reg_rd; + record_buf[1] = reg_rn; + record_buf[2] = reg_rs; + aarch64_insn_r->reg_rec_count = 3; + + ULONGEST dest_addr; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, + &dest_addr); + ULONGEST source_addr; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rs, + &source_addr); + LONGEST length; + regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, + &length); + + /* In a processor using algorithm option A, the length in Rn has an + inverted sign. */ + if (length < 0) + length *= -1; + + record_buf_mem[0] = length; + record_buf_mem[1] = dest_addr; + record_buf_mem[2] = length; + record_buf_mem[3] = source_addr; + aarch64_insn_r->mem_rec_count = 2; + } + else if ((op1 == 3 && op2 < 12) || (op1 == 3 && op2 < 12)) + { + /* Set instructions. */ + record_buf[0] = reg_rd; + record_buf[1] = reg_rn; + aarch64_insn_r->reg_rec_count = 2; + + ULONGEST address; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, + &address); + + LONGEST length; + regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, + &length); + + /* In a processor using algorithm option B, the length in Rn has an + inverted sign. */ + if (length < 0) + length *= -1; + + record_buf_mem[0] = length; + record_buf_mem[1] = address; + aarch64_insn_r->mem_rec_count = 1; + } + else + return AARCH64_RECORD_UNKNOWN; + + 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; +} + /* Record handler for load and store instructions. */ static unsigned int @@ -5465,6 +5545,10 @@ aarch64_record_load_store (aarch64_insn_decode_record *aarch64_insn_r) if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03) record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; } + /* Memory Copy and Memory Set instructions. */ + else if ((insn_bits24_27 & 1) == 1 && insn_bits28_29 == 1 + && insn_bits10_11 == 1 && !insn_bit21) + return aarch64_record_memcopy_memset (aarch64_insn_r); /* Advanced SIMD load/store instructions. */ else return aarch64_record_asimd_load_store (aarch64_insn_r);