From 7d842b6c956840f78871570207f15cf76a4b2354 Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
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

