gdb: LoongArch: add orig_a0 into register set

The basic support for LoongArch has been merged into the upstream Linux
kernel since 5.19-rc1 on June 5, 2022.  This commit adds orig_a0 which
is added into struct user_pt_regs [1] to match the upstream kernel, and
then the upstream GDB will work with the upstream kernel.

Note that orig_a0 was added into struct user_pt_regs in the development
cycle for merging LoongArch port into the upstream Linux kernel, so
earlier kernels (notably, the product kernel with version 4.19 used in
distros like UOS and Loongnix) don't have it.  Inspect
arch/loongarch/include/uapi/asm/ptrace.h in the kernel tree to make sure.
To build upstream GDB for a kernel lacking orig_a0, it's necessary to
revert this commit locally.

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/loongarch/include/uapi/asm/ptrace.h#n24

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
diff --git a/gdb/features/loongarch/base32.c b/gdb/features/loongarch/base32.c
index 7105c15..3fb35ef 100644
--- a/gdb/features/loongarch/base32.c
+++ b/gdb/features/loongarch/base32.c
@@ -41,6 +41,7 @@
   tdesc_create_reg (feature, "r29", regnum++, 1, "general", 32, "uint32");
   tdesc_create_reg (feature, "r30", regnum++, 1, "general", 32, "uint32");
   tdesc_create_reg (feature, "r31", regnum++, 1, "general", 32, "uint32");
+  tdesc_create_reg (feature, "orig_a0", regnum++, 1, "general", 32, "uint32");
   tdesc_create_reg (feature, "pc", regnum++, 1, "general", 32, "code_ptr");
   tdesc_create_reg (feature, "badv", regnum++, 1, "general", 32, "code_ptr");
   return regnum;
diff --git a/gdb/features/loongarch/base32.xml b/gdb/features/loongarch/base32.xml
index 5b00f8a..af47bbd 100644
--- a/gdb/features/loongarch/base32.xml
+++ b/gdb/features/loongarch/base32.xml
@@ -39,6 +39,7 @@
   <reg name="r29" bitsize="32" type="uint32" group="general"/>
   <reg name="r30" bitsize="32" type="uint32" group="general"/>
   <reg name="r31" bitsize="32" type="uint32" group="general"/>
+  <reg name="orig_a0" bitsize="32" type="uint32" group="general"/>
   <reg name="pc" bitsize="32" type="code_ptr" group="general"/>
   <reg name="badv" bitsize="32" type="code_ptr" group="general"/>
 </feature>
diff --git a/gdb/features/loongarch/base64.c b/gdb/features/loongarch/base64.c
index 63eee02..d84d425 100644
--- a/gdb/features/loongarch/base64.c
+++ b/gdb/features/loongarch/base64.c
@@ -41,6 +41,7 @@
   tdesc_create_reg (feature, "r29", regnum++, 1, "general", 64, "uint64");
   tdesc_create_reg (feature, "r30", regnum++, 1, "general", 64, "uint64");
   tdesc_create_reg (feature, "r31", regnum++, 1, "general", 64, "uint64");
+  tdesc_create_reg (feature, "orig_a0", regnum++, 1, "general", 64, "uint64");
   tdesc_create_reg (feature, "pc", regnum++, 1, "general", 64, "code_ptr");
   tdesc_create_reg (feature, "badv", regnum++, 1, "general", 64, "code_ptr");
   return regnum;
diff --git a/gdb/features/loongarch/base64.xml b/gdb/features/loongarch/base64.xml
index bef91e5..2d8a1f6 100644
--- a/gdb/features/loongarch/base64.xml
+++ b/gdb/features/loongarch/base64.xml
@@ -39,6 +39,7 @@
   <reg name="r29" bitsize="64" type="uint64" group="general"/>
   <reg name="r30" bitsize="64" type="uint64" group="general"/>
   <reg name="r31" bitsize="64" type="uint64" group="general"/>
+  <reg name="orig_a0" bitsize="64" type="uint64" group="general"/>
   <reg name="pc" bitsize="64" type="code_ptr" group="general"/>
   <reg name="badv" bitsize="64" type="code_ptr" group="general"/>
 </feature>
diff --git a/gdb/loongarch-linux-nat.c b/gdb/loongarch-linux-nat.c
index c341e71..1fd1af6 100644
--- a/gdb/loongarch-linux-nat.c
+++ b/gdb/loongarch-linux-nat.c
@@ -53,6 +53,7 @@
   elf_gregset_t regset;
 
   if (regnum == -1 || (regnum >= 0 && regnum < 32)
+      || regnum == LOONGARCH_ORIG_A0_REGNUM
       || regnum == LOONGARCH_PC_REGNUM
       || regnum == LOONGARCH_BADV_REGNUM)
   {
@@ -78,6 +79,7 @@
   elf_gregset_t regset;
 
   if (regnum == -1 || (regnum >= 0 && regnum < 32)
+      || regnum == LOONGARCH_ORIG_A0_REGNUM
       || regnum == LOONGARCH_PC_REGNUM
       || regnum == LOONGARCH_BADV_REGNUM)
   {
diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c
index 21fc67f..1076e93 100644
--- a/gdb/loongarch-linux-tdep.c
+++ b/gdb/loongarch-linux-tdep.c
@@ -48,6 +48,9 @@
 	  regcache->raw_supply (i, (const void *) buf);
 	}
 
+      buf = (const gdb_byte*) gprs + regsize * LOONGARCH_ORIG_A0_REGNUM;
+      regcache->raw_supply (LOONGARCH_ORIG_A0_REGNUM, (const void *) buf);
+
       buf = (const gdb_byte*) gprs + regsize * LOONGARCH_PC_REGNUM;
       regcache->raw_supply (LOONGARCH_PC_REGNUM, (const void *) buf);
 
@@ -57,6 +60,7 @@
   else if (regnum == 0)
     regcache->raw_supply_zeroed (0);
   else if ((regnum > 0 && regnum < 32)
+	   || regnum == LOONGARCH_ORIG_A0_REGNUM
 	   || regnum == LOONGARCH_PC_REGNUM
 	   || regnum == LOONGARCH_BADV_REGNUM)
     {
@@ -83,6 +87,9 @@
 	  regcache->raw_collect (i, (void *) buf);
 	}
 
+      buf = (gdb_byte *) gprs + regsize * LOONGARCH_ORIG_A0_REGNUM;
+      regcache->raw_collect (LOONGARCH_ORIG_A0_REGNUM, (void *) buf);
+
       buf = (gdb_byte *) gprs + regsize * LOONGARCH_PC_REGNUM;
       regcache->raw_collect (LOONGARCH_PC_REGNUM, (void *) buf);
 
@@ -90,6 +97,7 @@
       regcache->raw_collect (LOONGARCH_BADV_REGNUM, (void *) buf);
     }
   else if ((regnum >= 0 && regnum < 32)
+	   || regnum == LOONGARCH_ORIG_A0_REGNUM
 	   || regnum == LOONGARCH_PC_REGNUM
 	   || regnum == LOONGARCH_BADV_REGNUM)
     {
diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c
index f2f4e3b..76480ce 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -576,6 +576,7 @@
   for (int i = 0; i < 32; i++)
     valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++,
 					loongarch_r_normal_name[i] + 1);
+  valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, "orig_a0");
   valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, "pc");
   valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, "badv");
   if (!valid_p)
diff --git a/gdb/loongarch-tdep.h b/gdb/loongarch-tdep.h
index 54b34af..acf0191 100644
--- a/gdb/loongarch-tdep.h
+++ b/gdb/loongarch-tdep.h
@@ -35,9 +35,10 @@
   LOONGARCH_A0_REGNUM = 4,		/* First Argument/Return Value.  */
   LOONGARCH_A7_REGNUM = 11,		/* Seventh Argument/Syscall Number.  */
   LOONGARCH_FP_REGNUM = 22,		/* Frame Pointer.  */
-  LOONGARCH_PC_REGNUM = 32,		/* Program Counter.  */
-  LOONGARCH_BADV_REGNUM = 33,		/* Bad Vaddr for Addressing Exception.  */
-  LOONGARCH_LINUX_NUM_GREGSET = 45,	/* 32 GPR, PC, BADV, RESERVED 11.  */
+  LOONGARCH_ORIG_A0_REGNUM = 32,	/* Syscall's original arg0.  */
+  LOONGARCH_PC_REGNUM = 33,		/* Program Counter.  */
+  LOONGARCH_BADV_REGNUM = 34,		/* Bad Vaddr for Addressing Exception.  */
+  LOONGARCH_LINUX_NUM_GREGSET = 45,	/* 32 GPR, ORIG_A0, PC, BADV, RESERVED 10.  */
 };
 
 /* Register set definitions.  */