[Pdbg] [PATCH 13/14] gdbserver: use read-modify-write for put_mem that is not 8-byte aligned
Joel Stanley
joel at jms.id.au
Wed Mar 16 10:46:44 AEDT 2022
On Mon, 14 Mar 2022 at 04:18, Nicholas Piggin <npiggin at gmail.com> wrote:
>
> Not all targets have memory access that can support arbitrary byte
> writes. Use RMW for put_mem commands that are not 8-byte aligned.
Do we know which targets can/can't support unaligned byte writes?
>
> This should really either be done in the target accessor, or at least
> an alignment capability should be exposed to the caller. But for now
> this will allow sbefifo mem ops to work to set breakpoints (4-byte
> writes).
>
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
> ---
> src/pdbgproxy.c | 34 ++++++++++++++++++++++------------
> 1 file changed, 22 insertions(+), 12 deletions(-)
>
> diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
> index a37e997..e8aab70 100644
> --- a/src/pdbgproxy.c
> +++ b/src/pdbgproxy.c
> @@ -14,6 +14,7 @@
> #include <assert.h>
> #include <getopt.h>
> #include <errno.h>
> +#include <byteswap.h>
> #include <ccan/array_size/array_size.h>
>
> #include <bitutils.h>
> @@ -281,15 +282,15 @@ out:
> static void put_mem(uint64_t *stack, void *priv)
> {
> uint64_t addr, len;
> + uint64_t start_addr, end_addr;
> + uint64_t align = 8;
> + uint32_t *insn;
> uint8_t *data;
> + uint8_t *buf;
> uint8_t attn_opcode[] = {0x00, 0x00, 0x02, 0x00};
> + uint8_t gdb_break_opcode[] = {0x7d, 0x82, 0x10, 0x08};
> int err = 0;
>
> - if (littleendian) {
> - attn_opcode[1] = 0x02;
> - attn_opcode[2] = 0x00;
> - }
> -
> addr = stack[0];
> len = stack[1];
> data = (uint8_t *) &stack[2];
> @@ -301,8 +302,7 @@ static void put_mem(uint64_t *stack, void *priv)
> goto out;
> }
>
> -
> - if (len == 4 && stack[2] == 0x0810827d) {
> + if (len == 4 && !memcmp(data, gdb_break_opcode, 4)) {
> /* According to linux-ppc-low.c gdb only uses this
> * op-code for sw break points so we replace it with
> * the correct attn opcode which is what we need for
> @@ -318,17 +318,27 @@ static void put_mem(uint64_t *stack, void *priv)
> err = 2;
> goto out;
> }
> - } else {
> - stack[2] = __builtin_bswap64(stack[2]) >> 32;
> }
>
> - PR_INFO("put_mem 0x%016" PRIx64 " = 0x%016" PRIx64 "\n", addr, stack[2]);
> + if (len == 4 && littleendian) {
> + insn = (uint32_t *)data;
> + *insn = bswap_32(*insn);
> + }
>
> - if (mem_write(adu_target, addr, data, len, 0, false)) {
> + start_addr = addr & ~(align - 1);
> + end_addr = (addr + len + (align - 1)) & ~(align - 1);
Would some ALIGN_UP / ALIGN_DOWN macros make sense here?
> + if (addr != start_addr || (addr + len) != end_addr) {
> + buf = malloc(end_addr - start_addr);
> + mem_read(adu_target, start_addr, buf, end_addr - start_addr, 0, false);
> + memcpy(buf + (addr - start_addr), data, len);
> + } else {
> + buf = data;
> + }
> +
> + if (mem_write(adu_target, start_addr, buf, end_addr - start_addr, 0, false)) {
> PR_ERROR("Unable to write memory\n");
> err = 3;
> }
Needs to free buf if it was malloc'd.
> -
> out:
> if (err)
> send_response(fd, ERROR(EPERM));
> --
> 2.23.0
>
> --
> Pdbg mailing list
> Pdbg at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/pdbg
More information about the Pdbg
mailing list