From 7d842b6c956840f78871570207f15cf76a4b2354 Mon Sep 17 00:00:00 2001 From: Aditya Vidyadhar Kamath Date: Mon, 7 Nov 2022 04:53:15 -0600 Subject: [PATCH] Fix call functions command bug in 64-bit programs for AIX The issue is that when a user attempts to test the return type or print statements via the call FUNCNAME with parameters command any input be it parameter A or B is taken in little endian format from the GDB cache But AIX is using Big endian format This patch fixes the same issue --- gdb/rs6000-aix-nat.c | 146 ++++++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 38 deletions(-) diff --git a/gdb/rs6000-aix-nat.c b/gdb/rs6000-aix-nat.c index cb141427696..99e8af03877 100644 --- a/gdb/rs6000-aix-nat.c +++ b/gdb/rs6000-aix-nat.c @@ -194,6 +194,7 @@ fetch_register (struct regcache *regcache, int regno) { struct gdbarch *gdbarch = regcache->arch (); int addr[PPC_MAX_REGISTER_SIZE]; + long long addr64[PPC_MAX_REGISTER_SIZE]; int nr, isfloat; pid_t pid = regcache->ptid ().pid (); @@ -228,14 +229,19 @@ fetch_register (struct regcache *regcache, int regno) long long buf; rs6000_ptrace64 (PT_READ_GPR, pid, nr, 0, &buf); if (register_size (gdbarch, regno) == 8) - memcpy (addr, &buf, 8); + memcpy (addr64, &buf, 8); else - *addr = buf; + *addr64 = buf; } } if (!errno) - regcache->raw_supply (regno, (char *) addr); + { + if (!ARCH64 ()) + regcache->raw_supply (regno, (char *) addr); + else + regcache->raw_supply (regno, (char *) addr64); + } else { #if 0 @@ -252,57 +258,121 @@ static void store_register (struct regcache *regcache, int regno) { struct gdbarch *gdbarch = regcache->arch (); - int addr[PPC_MAX_REGISTER_SIZE]; - int nr, isfloat; - pid_t pid = regcache->ptid ().pid (); - - /* Fetch the register's value from the register cache. */ - regcache->raw_collect (regno, addr); - - /* -1 can be a successful return value, so infer errors from errno. */ + int addr32[PPC_MAX_REGISTER_SIZE]; + long addr64[PPC_MAX_REGISTER_SIZE]; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR addr; + CORE_ADDR original_addr; + size_t size; + gdb_byte *little_end_buf; + pid_t pid; + int i; + int isfloat; + long big_end_buf = INT_MIN; errno = 0; - nr = regmap (gdbarch, regno, &isfloat); + /* Get the address of the register. */ + addr = regmap (gdbarch, regno, &isfloat); + + if (addr == (CORE_ADDR)-1 + || gdbarch_cannot_store_register (gdbarch, regno)) + return; + + pid = regcache->ptid ().pid (); + + size = register_size (gdbarch, regno); + little_end_buf = (gdb_byte *) alloca (size); + + /* Register number R3 to R10 in AIX belongs to + function parameters. If a user attempts to + give input via call command and in 64 bit mode + the value in the buffer is little endian but + in AIX we use big endian. Hence if R3 to R10 + registers are used in 64 bit mode we need to + re align from little endian to big endian. + Otherwise it can be in a 64 bit or 32 bit buffer + depending on the architecture bit mode of the + user program. */ + + if (regno <= 10 && regno >= 3 && ARCH64 ()) + regcache->raw_collect (regno, little_end_buf); + else if (ARCH64 ()) + regcache->raw_collect (regno, addr64); + else + regcache->raw_collect (regno, addr32); + + /* Save the original address of the register. */ + original_addr = addr; /* Floating-point registers. */ if (isfloat) - rs6000_ptrace32 (PT_WRITE_FPR, pid, addr, nr, 0); + rs6000_ptrace32 (PT_WRITE_FPR, pid, *little_end_buf, addr, 0); /* Bogus register number. */ - else if (nr < 0) + if (addr < 0) { if (regno >= gdbarch_num_regs (gdbarch)) - gdb_printf (gdb_stderr, - "gdb error: register no %d not implemented.\n", - regno); + gdb_printf (gdb_stderr, + "gdb error: register no %d not implemented.\n", + regno); } + /* Fixed-point registers in 32 bit mode. */ + else if (!ARCH64 ()) + rs6000_ptrace32 (PT_WRITE_GPR, pid, (int *) addr, *addr32, 0); - /* Fixed-point registers. */ + /* Fixed-point registers in 64 bit mode. */ else + { + /* Function parameters to be changed from little to big endian. */ + if (regno <= 10 && regno >= 3) { + for (i = 0; i < size; i += sizeof (PTRACE_TYPE_RET)) + { + size_t chunk = std::min (sizeof (PTRACE_TYPE_RET), size - i); + PTRACE_TYPE_RET val; + + val = extract_unsigned_integer (little_end_buf + i, chunk, byte_order); + errno = 0; + + /* Realign chunck by chunk in 8 bits. */ + + if (register_size (gdbarch, regno) == 8) + { + if (val != 0) + { + /* Either higher 32 bits or higher 32 bits are 0. */ + if (big_end_buf == INT_MIN || big_end_buf == 0) + big_end_buf = val; + + /* Lower 32 bits. */ + else if (big_end_buf != INT_MIN) + { + big_end_buf <<= 8; + big_end_buf |= val; + } + } + + /* Copy 0 only if the actual value is 0. */ + else if (val == 0 && big_end_buf == INT_MIN) + big_end_buf = val; + } + else + big_end_buf = val; + addr += sizeof (PTRACE_TYPE_RET); + } + /* The PT_WRITE_GPR operation is rather odd. For 32-bit inferiors, - the register's value is passed by value, but for 64-bit inferiors, - the address of a buffer containing the value is passed. */ - if (!ARCH64 ()) - rs6000_ptrace32 (PT_WRITE_GPR, pid, (int *) nr, *addr, 0); - else - { - /* PT_WRITE_GPR requires the buffer parameter to point to an 8-byte - area, even if the register is really only 32 bits. */ - long long buf; - if (register_size (gdbarch, regno) == 8) - memcpy (&buf, addr, 8); - else - buf = *addr; - rs6000_ptrace64 (PT_WRITE_GPR, pid, nr, 0, &buf); - } - } + the register's value is passed by value, but for 64-bit inferiors, + the address of a buffer containing the value is passed. */ - if (errno) - { - perror (_("ptrace write")); - errno = 0; + /* PT_WRITE_GPR requires the buffer parameter to point to an 8-byte + area, even if the register is really only 32 bits. */ + + rs6000_ptrace64 (PT_WRITE_GPR, pid, (long *)original_addr, 0, &big_end_buf); } + else + rs6000_ptrace64 (PT_WRITE_GPR, pid, (long *)original_addr, 0, addr64); + } } /* Read from the inferior all registers if REGNO == -1 and just register -- 2.31.1