public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Christophe Lyon <christophe.lyon@linaro.org>
To: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH 1/5] gdb/aarch64: Implement software single stepping for MOPS instructions
Date: Mon, 6 May 2024 11:29:50 +0200	[thread overview]
Message-ID: <CAPS5khbR9jJngxSkGipXpPbzOSwNErwE9LgkK1Q+yCpAnGyWZQ@mail.gmail.com> (raw)
In-Reply-To: <20240504000521.314531-2-thiago.bauermann@linaro.org>

On Sat, 4 May 2024 at 02:05, Thiago Jung Bauermann
<thiago.bauermann@linaro.org> wrote:
>
> The AArch64 MOPS (Memory Operation) instructions provide a standardised
> instruction sequence to perform a memset, memcpy or memmove.  A sequence is
> always composed of three instructions: a prologue instruction, a main
> instruction and an epilogue instruction.  As an illustration, here are the
> implementations of these memory operations in glibc 2.39:
>
>   (gdb) disassemble/r
>   Dump of assembler code for function __memset_mops:
>   => 0x0000fffff7e8d780 <+0>:     d503201f        nop
>      0x0000fffff7e8d784 <+4>:     aa0003e3        mov     x3, x0
>      0x0000fffff7e8d788 <+8>:     19c10443        setp    [x3]!, x2!, x1
>      0x0000fffff7e8d78c <+12>:    19c14443        setm    [x3]!, x2!, x1
>      0x0000fffff7e8d790 <+16>:    19c18443        sete    [x3]!, x2!, x1
>      0x0000fffff7e8d794 <+20>:    d65f03c0        ret
>   End of assembler dump.
>
>   (gdb) disassemble/r
>   Dump of assembler code for function __memcpy_mops:
>   => 0x0000fffff7e8c580 <+0>:     d503201f        nop
>      0x0000fffff7e8c584 <+4>:     aa0003e3        mov     x3, x0
>      0x0000fffff7e8c588 <+8>:     19010443        cpyfp   [x3]!, [x1]!, x2!
>      0x0000fffff7e8c58c <+12>:    19410443        cpyfm   [x3]!, [x1]!, x2!
>      0x0000fffff7e8c590 <+16>:    19810443        cpyfe   [x3]!, [x1]!, x2!
>      0x0000fffff7e8c594 <+20>:    d65f03c0        ret
>   End of assembler dump.
>
>   (gdb) disassemble/r
>   Dump of assembler code for function __memmove_mops:
>   => 0x0000fffff7e8d180 <+0>:     d503201f        nop
>      0x0000fffff7e8d184 <+4>:     aa0003e3        mov     x3, x0
>      0x0000fffff7e8d188 <+8>:     1d010443        cpyp    [x3]!, [x1]!, x2!
>      0x0000fffff7e8d18c <+12>:    1d410443        cpym    [x3]!, [x1]!, x2!
>      0x0000fffff7e8d190 <+16>:    1d810443        cpye    [x3]!, [x1]!, x2!
>      0x0000fffff7e8d194 <+20>:    d65f03c0        ret
>   End of assembler dump.
>
> The Arm Architecture Reference Manual says that "the prologue, main, and
> epilogue instructions are expected to be run in succession and to appear
> consecutively in memory".  Therefore GDB needs to treat them as an atomic
> instruction sequence, and also can't do displaced stepping with them.
>
> This patch implements support for executing the sequence atomically, and
> also disables displaced step on them.
>
> PR tdep/31666
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31666
> ---
>  gdb/aarch64-tdep.c | 107 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 105 insertions(+), 2 deletions(-)
>
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index 8d0553f3d7cd..e920cea49066 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3444,6 +3444,104 @@ value_of_aarch64_user_reg (const frame_info_ptr &frame, const void *baton)
>    return value_of_register (*reg_p, get_next_frame_sentinel_okay (frame));
>  }
>
> +/* Single step through MOPS instruction sequences on AArch64.  */
> +
> +static std::vector<CORE_ADDR>
> +aarch64_software_single_step_mops (struct regcache *regcache, CORE_ADDR loc,
> +                                  uint32_t insn)
> +{
> +  const int insn_size = 4;
> +  struct gdbarch *gdbarch = regcache->arch ();
> +  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
> +  uint8_t o0 = bit (insn, 21);
> +  uint8_t op1 = bits (insn, 22, 23);
> +  uint8_t op2 = bits (insn, 12, 15);
> +
> +  /* Look for the prologue instruction that begins the sequence.  */
> +
> +       /* CPYFP* */
> +  if (!((o0 == 0 && op1 == 0)
> +       /* SETP* */
> +       || (o0 == 0 && op1 == 3 && op2 < 4)
> +       /* CPYP* */
> +       || (o0 == 1 && op1 == 0)
> +       /* SETGP* */
> +       || (o0 == 1 && op1 == 3 && op2 < 4)))
> +    /* Prologue instruction not found.  */
> +    return {};
> +
> +  /* Now look for the main instruction in the middle of the sequence.  */
> +
> +  loc += insn_size;
> +  ULONGEST insn_from_memory;
> +  if (!safe_read_memory_unsigned_integer (loc, insn_size,
> +                                         byte_order_for_code,
> +                                         &insn_from_memory))
> +    {
> +      /* Assume we don't have a MOPS sequence, as we couldn't read the
> +        instruction in this location.  */
> +      return {};
> +    }
> +
> +  insn = insn_from_memory;
> +  aarch64_inst inst;
> +  if (aarch64_decode_insn (insn, &inst, 1, nullptr) != 0)
> +    return {};
> +  if (!AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
> +    return {};
> +
> +  o0 = bit (insn, 21);
> +  op1 = bits (insn, 22, 23);
> +  op2 = bits (insn, 12, 15);
> +
> +       /* CPYFM* */
> +  if (!((o0 == 0 && op1 == 1)
> +       /* SETM* */
> +       || (o0 == 0 && op1 == 3 && op2 >= 4 && op2 < 8)
> +       /* CPYM* */
> +       || (o0 == 1 && op1 == 1)
> +       /* SETGM* */
> +       || (o0 == 1 && op1 == 3 && op2 >= 4 && op2 < 8)))
> +    /* Main instruction not found.  */
> +    return {};
> +
> +  /* Now look for the epilogue instruction that ends the sequence.  */
> +
> +  loc += insn_size;
> +  if (!safe_read_memory_unsigned_integer (loc, insn_size,
> +                                         byte_order_for_code,
> +                                         &insn_from_memory))
> +    {
> +      /* Assume we don't have a MOPS sequence, as we couldn't read the
> +        instruction in this location.  */
> +      return {};
> +    }
> +
> +  insn = insn_from_memory;
> +  if (aarch64_decode_insn (insn, &inst, 1, nullptr) != 0)
> +    return {};
> +  if (!AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
> +    return {};
> +
> +  o0 = bit (insn, 21);
> +  op1 = bits (insn, 22, 23);
> +  op2 = bits (insn, 12, 15);
> +
> +       /* CPYFE* */
> +  if (!((o0 == 0 && op1 == 2)
> +       /* SETE* (op2 >= 12 is unallocated space) */
> +       || (o0 == 0 && op1 == 3 && op2 >= 8 && op2 < 12)
> +       /* CPYE* */
> +       || (o0 == 1 && op1 == 2)
> +       /* SETGE* (op2 >= 12 is unallocated space) */
> +       || (o0 == 1 && op1 == 3 && op2 >= 8 && op2 < 12)))
> +    /* Epilogue instruction not found.  */
> +    return {};
> +
> +  /* Insert breakpoint after the end of the atomic sequence.  */
> +  return { loc + insn_size };
> +}
> +
>  /* Implement the "software_single_step" gdbarch method, needed to
>     single step through atomic sequences on AArch64.  */
>
> @@ -3479,6 +3577,9 @@ aarch64_software_single_step (struct regcache *regcache)
>    if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
>      return {};
>
> +  if (AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
> +    return aarch64_software_single_step_mops (regcache, loc, insn);
> +
>    /* Look for a Load Exclusive instruction which begins the sequence.  */
>    if (inst.opcode->iclass != ldstexcl || bit (insn, 22) == 0)
>      return {};
> @@ -3808,8 +3909,10 @@ aarch64_displaced_step_copy_insn (struct gdbarch *gdbarch,
>    if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
>      return NULL;
>
> -  /* Look for a Load Exclusive instruction which begins the sequence.  */
> -  if (inst.opcode->iclass == ldstexcl && bit (insn, 22))
> +  /* Look for a Load Exclusive instruction which begins the sequence,
> +     or for a MOPS instruction.  */
> +  if ((inst.opcode->iclass == ldstexcl && bit (insn, 22))
> +      || AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))

Sorry for the naive question: doesn't this check that the CPU supports
MOPS, rather than the instruction sequence is a MOPS one?

Thanks,

Christophe

>      {
>        /* We can't displaced step atomic sequences.  */
>        return NULL;

  reply	other threads:[~2024-05-06  9:30 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-04  0:05 [PATCH 0/5] Add support for AArch64 " Thiago Jung Bauermann
2024-05-04  0:05 ` [PATCH 1/5] gdb/aarch64: Implement software single stepping for " Thiago Jung Bauermann
2024-05-06  9:29   ` Christophe Lyon [this message]
2024-05-07  0:56     ` Thiago Jung Bauermann
2024-05-04  0:05 ` [PATCH 2/5] gdb/aarch64: Add record support " Thiago Jung Bauermann
2024-05-04  0:05 ` [PATCH 3/5] gdb/testsuite: Add gdb.arch/aarch64-mops-watchpoint.exp Thiago Jung Bauermann
2024-05-04  0:05 ` [PATCH 4/5] gdb/testsuite: Add gdb.arch/aarch64-mops-atomic-inst.exp Thiago Jung Bauermann
2024-05-06  9:42   ` Christophe Lyon
2024-05-07  2:10     ` Thiago Jung Bauermann
2024-05-04  0:05 ` [PATCH 5/5] gdb/testsuite: Add gdb.reverse/aarch64-mops.exp Thiago Jung Bauermann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAPS5khbR9jJngxSkGipXpPbzOSwNErwE9LgkK1Q+yCpAnGyWZQ@mail.gmail.com \
    --to=christophe.lyon@linaro.org \
    --cc=gdb-patches@sourceware.org \
    --cc=thiago.bauermann@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).