From da451baee5e701949fd570904998d456c8bdc744 Mon Sep 17 00:00:00 2001
From: Hui Li <lihui@loongson.cn>
Date: Tue, 10 Jan 2023 06:13:10 +0800
Subject: [PATCH 1/2] Add support for 64-bit LoongArch architecture

Signed-off-by: Hui Li <lihui@loongson.cn>
---
 NEWS                                         |  1 +
 configure                                    |  7 +++
 configure.ac                                 |  5 ++
 src/Makefile.am                              | 15 +++++
 src/linux/loongarch64/arch_defs_.h           |  8 +++
 src/linux/loongarch64/arch_fpregset.c        | 36 +++++++++++
 src/linux/loongarch64/arch_fpregset.h        | 15 +++++
 src/linux/loongarch64/arch_prstatus_regset.c | 49 +++++++++++++++
 src/linux/loongarch64/arch_prstatus_regset.h | 15 +++++
 src/linux/loongarch64/arch_regs.c            | 11 ++++
 src/linux/loongarch64/get_error.c            | 19 ++++++
 src/linux/loongarch64/get_scno.c             | 14 +++++
 src/linux/loongarch64/get_syscall_args.c     | 19 ++++++
 src/linux/loongarch64/ioctls_arch0.h         |  1 +
 src/linux/loongarch64/ioctls_inc0.h          |  1 +
 src/linux/loongarch64/raw_syscall.h          | 29 +++++++++
 src/linux/loongarch64/set_error.c            | 20 ++++++
 src/linux/loongarch64/set_scno.c             | 15 +++++
 src/linux/loongarch64/syscallent.h           |  8 +++
 src/xlat/audit_arch.in                       |  2 +
 src/xlat/elf_em.in                           |  1 +
 tests/ptrace.c                               | 65 +++++++++++++++++++-
 22 files changed, 355 insertions(+), 1 deletion(-)
 create mode 100644 src/linux/loongarch64/arch_defs_.h
 create mode 100644 src/linux/loongarch64/arch_fpregset.c
 create mode 100644 src/linux/loongarch64/arch_fpregset.h
 create mode 100644 src/linux/loongarch64/arch_prstatus_regset.c
 create mode 100644 src/linux/loongarch64/arch_prstatus_regset.h
 create mode 100644 src/linux/loongarch64/arch_regs.c
 create mode 100644 src/linux/loongarch64/get_error.c
 create mode 100644 src/linux/loongarch64/get_scno.c
 create mode 100644 src/linux/loongarch64/get_syscall_args.c
 create mode 100644 src/linux/loongarch64/ioctls_arch0.h
 create mode 100644 src/linux/loongarch64/ioctls_inc0.h
 create mode 100644 src/linux/loongarch64/raw_syscall.h
 create mode 100644 src/linux/loongarch64/set_error.c
 create mode 100644 src/linux/loongarch64/set_scno.c
 create mode 100644 src/linux/loongarch64/syscallent.h

diff --git a/NEWS b/NEWS
index f88de1d..d6727a4 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Noteworthy changes in release 5.14 (2021-09-02)
   * Updated lists of BPF_*, IORING_*, MADV_*, MOUNT_ATTR_*, SCTP_*,
     and UFFD_* constants.
   * Updated lists of ioctl commands from Linux 5.14.
+  * Added 64-bit LoongArch architecture support.
 
 * Bug fixes
   * Fixed build using bionic libc.
diff --git a/configure b/configure
index f19e397..88cd0b9 100755
--- a/configure
+++ b/configure
@@ -6049,6 +6049,13 @@ ia64)
 
 $as_echo "#define IA64 1" >>confdefs.h
 
+	;;
+loongarch64)
+	arch=loongarch64
+	karch=loongarch
+
+$as_echo "#define LOONGARCH64 1" >>confdefs.h
+
 	;;
 m68k)
 	arch=m68k
diff --git a/configure.ac b/configure.ac
index 2771c0f..def3bb2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -110,6 +110,11 @@ ia64)
 	arch=ia64
 	AC_DEFINE([IA64], 1, [Define for the IA64 architecture.])
 	;;
+loongarch64)
+	arch=loongarch64
+	karch=loongarch
+	AC_DEFINE([LOONGARCH64], 1, [Define for the 64-bit LoongArch architecture.])
+	;;
 m68k)
 	arch=m68k
 	AC_DEFINE([M68K], 1, [Define for the m68k architecture.])
diff --git a/src/Makefile.am b/src/Makefile.am
index b7e74a7..dc38851 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -634,6 +634,21 @@ EXTRA_DIST =				\
 	linux/ia64/syscallent.h		\
 	linux/ia64/syscallent_base_nr.h	\
 	linux/ia64/userent.h		\
+	linux/loongarch64/arch_defs_.h	\
+	linux/loongarch64/arch_fpregset.c	\
+	linux/loongarch64/arch_fpregset.h	\
+	linux/loongarch64/arch_prstatus_regset.c	\
+	linux/loongarch64/arch_prstatus_regset.h	\
+	linux/loongarch64/arch_regs.c	\
+	linux/loongarch64/get_error.c	\
+	linux/loongarch64/get_scno.c	\
+	linux/loongarch64/get_syscall_args.c	\
+	linux/loongarch64/ioctls_arch0.h	\
+	linux/loongarch64/ioctls_inc0.h	\
+	linux/loongarch64/raw_syscall.h	\
+	linux/loongarch64/set_error.c	\
+	linux/loongarch64/set_scno.c	\
+	linux/loongarch64/syscallent.h	\
 	linux/m68k/arch_defs_.h		\
 	linux/m68k/arch_regs.c		\
 	linux/m68k/arch_rt_sigframe.c	\
diff --git a/src/linux/loongarch64/arch_defs_.h b/src/linux/loongarch64/arch_defs_.h
new file mode 100644
index 0000000..ffb5733
--- /dev/null
+++ b/src/linux/loongarch64/arch_defs_.h
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#define PERSONALITY0_AUDIT_ARCH { AUDIT_ARCH_LOONGARCH64, 0 }
diff --git a/src/linux/loongarch64/arch_fpregset.c b/src/linux/loongarch64/arch_fpregset.c
new file mode 100644
index 0000000..b17a407
--- /dev/null
+++ b/src/linux/loongarch64/arch_fpregset.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+static void
+arch_decode_fpregset(struct tcb *const tcp,
+		     const kernel_ulong_t addr,
+		     const kernel_ulong_t size)
+{
+	struct_fpregset regs;
+	const size_t fetch_size = MIN(sizeof(regs), size);
+
+	if (!size || size & 7) {
+		printaddr(addr);
+	} else if (!umoven_or_printaddr(tcp, addr, fetch_size, &regs)) {
+		tprint_struct_begin();
+		PRINT_FIELD_ARRAY_UPTO(regs, fpr, fetch_size / 8, tcp,
+				       print_xint64_array_member);
+		if (fetch_size > offsetof(struct_fpregset, fcc)) {
+			tprint_struct_next();
+			PRINT_FIELD_X(regs, fcc);
+		}
+		if (fetch_size > offsetof(struct_fpregset, fcsr)) {
+			tprint_struct_next();
+			PRINT_FIELD_X(regs, fcsr);
+		}
+		if (size > sizeof(regs)) {
+			tprint_struct_next();
+			tprint_more_data_follows();
+		}
+		tprint_struct_end();
+	}
+}
diff --git a/src/linux/loongarch64/arch_fpregset.h b/src/linux/loongarch64/arch_fpregset.h
new file mode 100644
index 0000000..998b40f
--- /dev/null
+++ b/src/linux/loongarch64/arch_fpregset.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef STRACE_ARCH_FPREGSET_H
+# define STRACE_ARCH_FPREGSET_H
+
+typedef struct user_fp_state struct_fpregset;
+
+# define HAVE_ARCH_FPREGSET 1
+
+#endif /* !STRACE_ARCH_FPREGSET_H */
diff --git a/src/linux/loongarch64/arch_prstatus_regset.c b/src/linux/loongarch64/arch_prstatus_regset.c
new file mode 100644
index 0000000..f5a0c57
--- /dev/null
+++ b/src/linux/loongarch64/arch_prstatus_regset.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+static void
+arch_decode_prstatus_regset(struct tcb *const tcp,
+			    const kernel_ulong_t addr,
+			    const kernel_ulong_t size)
+{
+	struct_prstatus_regset regs;
+	const size_t fetch_size = MIN(sizeof(regs), size);
+
+	if (!size || size & 7) {
+		printaddr(addr);
+	} else if (!umoven_or_printaddr(tcp, addr, fetch_size, &regs)) {
+		tprint_struct_begin();
+		PRINT_FIELD_ARRAY_UPTO(regs, regs,
+				       fetch_size / 8, tcp,
+				       print_xint64_array_member);
+		if (fetch_size > offsetof(struct_prstatus_regset, orig_a0)) {
+			tprint_struct_next();
+			PRINT_FIELD_X(regs, orig_a0);
+		}
+		if (fetch_size > offsetof(struct_prstatus_regset, csr_era)) {
+			tprint_struct_next();
+			PRINT_FIELD_X(regs, csr_era);
+		}
+		if (fetch_size > offsetof(struct_prstatus_regset, csr_badv)) {
+			tprint_struct_next();
+			PRINT_FIELD_X(regs, csr_badv);
+		}
+		const size_t offset_of_reserved =
+			offsetof(struct_prstatus_regset, reserved);
+		if (fetch_size > offset_of_reserved) {
+			tprint_struct_next();
+			PRINT_FIELD_ARRAY_UPTO(regs, reserved,
+					       (fetch_size - offset_of_reserved) / 8,
+					       tcp, print_xint64_array_member);
+		}
+		if (size > sizeof(regs)) {
+			tprint_struct_next();
+			tprint_more_data_follows();
+		}
+		tprint_struct_end();
+	}
+}
diff --git a/src/linux/loongarch64/arch_prstatus_regset.h b/src/linux/loongarch64/arch_prstatus_regset.h
new file mode 100644
index 0000000..e7eb64b
--- /dev/null
+++ b/src/linux/loongarch64/arch_prstatus_regset.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef STRACE_ARCH_PRSTATUS_REGSET_H
+# define STRACE_ARCH_PRSTATUS_REGSET_H
+
+typedef struct user_pt_regs struct_prstatus_regset;
+
+# define HAVE_ARCH_PRSTATUS_REGSET 1
+
+#endif /* !STRACE_ARCH_PRSTATUS_REGSET_H */
diff --git a/src/linux/loongarch64/arch_regs.c b/src/linux/loongarch64/arch_regs.c
new file mode 100644
index 0000000..509ac8e
--- /dev/null
+++ b/src/linux/loongarch64/arch_regs.c
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+static struct user_pt_regs loongarch_regs;
+#define ARCH_REGS_FOR_GETREGSET loongarch_regs
+#define ARCH_PC_REG loongarch_regs.csr_era
+#define ARCH_SP_REG loongarch_regs.regs[3]
diff --git a/src/linux/loongarch64/get_error.c b/src/linux/loongarch64/get_error.c
new file mode 100644
index 0000000..b52ae28
--- /dev/null
+++ b/src/linux/loongarch64/get_error.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "negated_errno.h"
+
+static void
+arch_get_error(struct tcb *tcp, const bool check_errno)
+{
+	if (check_errno && is_negated_errno(loongarch_regs.regs[4])) {
+		tcp->u_rval = -1;
+		tcp->u_error = -loongarch_regs.regs[4];
+	} else {
+		tcp->u_rval = loongarch_regs.regs[4];
+	}
+}
diff --git a/src/linux/loongarch64/get_scno.c b/src/linux/loongarch64/get_scno.c
new file mode 100644
index 0000000..cb0f42c
--- /dev/null
+++ b/src/linux/loongarch64/get_scno.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+/* Return codes: 1 - ok, 0 - ignore, other - error. */
+static int
+arch_get_scno(struct tcb *tcp)
+{
+	tcp->scno = loongarch_regs.regs[11];
+	return 1;
+}
diff --git a/src/linux/loongarch64/get_syscall_args.c b/src/linux/loongarch64/get_syscall_args.c
new file mode 100644
index 0000000..e97aa72
--- /dev/null
+++ b/src/linux/loongarch64/get_syscall_args.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+/* Return -1 on error or 1 on success (never 0!). */
+static int
+arch_get_syscall_args(struct tcb *tcp)
+{
+	tcp->u_arg[0] = loongarch_regs.orig_a0;
+	tcp->u_arg[1] = loongarch_regs.regs[5];
+	tcp->u_arg[2] = loongarch_regs.regs[6];
+	tcp->u_arg[3] = loongarch_regs.regs[7];
+	tcp->u_arg[4] = loongarch_regs.regs[8];
+	tcp->u_arg[5] = loongarch_regs.regs[9];
+	return 1;
+}
diff --git a/src/linux/loongarch64/ioctls_arch0.h b/src/linux/loongarch64/ioctls_arch0.h
new file mode 100644
index 0000000..59d8aaa
--- /dev/null
+++ b/src/linux/loongarch64/ioctls_arch0.h
@@ -0,0 +1 @@
+/* Generated by ioctls_gen.sh from definitions found in $linux/arch/loongarch/include/ tree. */
diff --git a/src/linux/loongarch64/ioctls_inc0.h b/src/linux/loongarch64/ioctls_inc0.h
new file mode 100644
index 0000000..6028afb
--- /dev/null
+++ b/src/linux/loongarch64/ioctls_inc0.h
@@ -0,0 +1 @@
+#include "../64/ioctls_inc.h"
diff --git a/src/linux/loongarch64/raw_syscall.h b/src/linux/loongarch64/raw_syscall.h
new file mode 100644
index 0000000..1227778
--- /dev/null
+++ b/src/linux/loongarch64/raw_syscall.h
@@ -0,0 +1,29 @@
+/*
+ * Raw syscalls.
+ *
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef STRACE_RAW_SYSCALL_H
+# define STRACE_RAW_SYSCALL_H
+
+# include "kernel_types.h"
+
+static inline kernel_ulong_t
+raw_syscall_0(const kernel_ulong_t nr, kernel_ulong_t *err)
+{
+	*err = 0;
+	register kernel_ulong_t a7 __asm__("a7") = nr;
+	register kernel_ulong_t a0 __asm__("a0");
+	__asm__ __volatile__("syscall 0"
+			     : "=r"(a0)
+			     : "r"(a7)
+			     : "memory");
+	return a0;
+}
+# define raw_syscall_0 raw_syscall_0
+
+#endif /* !STRACE_RAW_SYSCALL_H */
diff --git a/src/linux/loongarch64/set_error.c b/src/linux/loongarch64/set_error.c
new file mode 100644
index 0000000..aa83a3e
--- /dev/null
+++ b/src/linux/loongarch64/set_error.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+static int
+arch_set_error(struct tcb *tcp)
+{
+	loongarch_regs.regs[4] = -tcp->u_error;
+	return set_regs(tcp->pid);
+}
+
+static int
+arch_set_success(struct tcb *tcp)
+{
+	loongarch_regs.regs[4] = tcp->u_rval;
+	return set_regs(tcp->pid);
+}
diff --git a/src/linux/loongarch64/set_scno.c b/src/linux/loongarch64/set_scno.c
new file mode 100644
index 0000000..d338f20
--- /dev/null
+++ b/src/linux/loongarch64/set_scno.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+static int
+arch_set_scno(struct tcb *tcp, kernel_ulong_t scno)
+{
+	if (ptrace_syscall_info_is_valid() && get_regs(tcp) < 0)
+		return -1;
+	loongarch_regs.regs[11] = scno;
+	return set_regs(tcp->pid);
+}
diff --git a/src/linux/loongarch64/syscallent.h b/src/linux/loongarch64/syscallent.h
new file mode 100644
index 0000000..5ab228b
--- /dev/null
+++ b/src/linux/loongarch64/syscallent.h
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2021-2022 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "../64/syscallent.h"
diff --git a/src/xlat/audit_arch.in b/src/xlat/audit_arch.in
index 63d3fe5..0760eb7 100644
--- a/src/xlat/audit_arch.in
+++ b/src/xlat/audit_arch.in
@@ -25,6 +25,8 @@ AUDIT_ARCH_H8300	(EM_H8_300) /* Removed in v3.13-rc1~130^2~2 */
 AUDIT_ARCH_HEXAGON	(EM_HEXAGON)
 AUDIT_ARCH_I386		(EM_386|__AUDIT_ARCH_LE)
 AUDIT_ARCH_IA64		(EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+AUDIT_ARCH_LOONGARCH32	(EM_LOONGARCH|__AUDIT_ARCH_LE)
+AUDIT_ARCH_LOONGARCH64	(EM_LOONGARCH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
 AUDIT_ARCH_M32R		(EM_M32R)
 AUDIT_ARCH_M68K		(EM_68K)
 AUDIT_ARCH_MICROBLAZE	(EM_MICROBLAZE)
diff --git a/src/xlat/elf_em.in b/src/xlat/elf_em.in
index 9ffbcd6..18f4c9a 100644
--- a/src/xlat/elf_em.in
+++ b/src/xlat/elf_em.in
@@ -190,6 +190,7 @@ EM_AMDGPU		224 /* AMD GPU architecture */
 EM_RISCV		243 /* RISC-V */
 EM_BPF			247 /* Linux BPF - in-kernel virtual machine */
 EM_CSKY			252 /* C-SKY */
+EM_LOONGARCH		258 /* LoongArch */
 EM_AVR32		0x18ad /* Atmel AVR32, removed in v4.12-rc1~159^2~5 */
 EM_FRV			0x5441 /* Fujitsu FR-V */
 EM_OR32			0x8472 /* arch/openrisc/include/uapi/asm/elf.h */
diff --git a/tests/ptrace.c b/tests/ptrace.c
index 8c98219..235aed9 100644
--- a/tests/ptrace.c
+++ b/tests/ptrace.c
@@ -185,7 +185,7 @@ test_peeksiginfo(int pid, const unsigned long bad_request)
 # define TRACEE_REGS_STRUCT struct pt_regs
 #elif defined __arm__
 # define TRACEE_REGS_STRUCT struct pt_regs
-#elif defined __arm64__ || defined __aarch64__
+#elif defined __arm64__ || defined __aarch64__ || defined __loongarch__
 # define TRACEE_REGS_STRUCT struct user_pt_regs
 #elif defined __s390__ || defined __s390x__
 # define TRACEE_REGS_STRUCT s390_regs
@@ -826,11 +826,51 @@ print_prstatus_regset(const void *const rs, const size_t size)
 		PRINT_FIELD_X(*regs, cp0_cause);
 	}
 
+# elif defined __loongarch__
+
+	if (size > offsetof(TRACEE_REGS_STRUCT, regs)) {
+		const size_t len = size - offsetof(TRACEE_REGS_STRUCT, regs);
+		fputs("regs=[", stdout);
+		for (unsigned int i = 0; i < ARRAY_SIZE(regs->regs); ++i) {
+			if (len > i * sizeof(regs->regs[i])) {
+				if (i)
+					fputs(", ", stdout);
+				PRINT_VAL_X(regs->regs[i]);
+			}
+		}
+		fputs("]", stdout);
+	}
+	if (size >= offsetofend(TRACEE_REGS_STRUCT, orig_a0)) {
+		fputs(", ", stdout);
+		PRINT_FIELD_X(*regs, orig_a0);
+	}
+	if (size >= offsetofend(TRACEE_REGS_STRUCT, csr_era)) {
+		fputs(", ", stdout);
+		PRINT_FIELD_X(*regs, csr_era);
+	}
+	if (size >= offsetofend(TRACEE_REGS_STRUCT, csr_badv)) {
+		fputs(", ", stdout);
+		PRINT_FIELD_X(*regs, csr_badv);
+	}
+	if (size > offsetof(TRACEE_REGS_STRUCT, reserved)) {
+		const size_t len = size - offsetof(TRACEE_REGS_STRUCT, reserved);
+		fputs(", reserved=[", stdout);
+		for (unsigned int i = 0; i < ARRAY_SIZE(regs->reserved); ++i) {
+			if (len > i * sizeof(regs->reserved[i])) {
+				if (i)
+					fputs(", ", stdout);
+				PRINT_VAL_X(regs->reserved[i]);
+			}
+		}
+		fputs("]", stdout);
+	}
+
 # endif /*
 	   __aarch64__ ||
 	   __arm64__ ||
 	   __arm__ ||
 	   __i386__ ||
+	   __loongarch__ ||
 	   __mips__ ||
 	   __powerpc64__ ||
 	   __powerpc__ ||
@@ -1066,6 +1106,8 @@ typedef struct {
 	uint64_t fpscr;
 } ppc_fpregs_struct;
 # define TRACEE_REGS_STRUCT ppc_fpregs_struct
+#elif defined __loongarch__
+# define TRACEE_REGS_STRUCT struct user_fp_state
 #endif
 
 static void
@@ -1209,8 +1251,29 @@ print_fpregset(const void *const rs, const size_t size)
 		PRINT_FIELD_X(*regs, fpscr);
 	}
 
+# elif defined __loongarch__
+
+	fputs("fpr=[", stdout);
+	for (unsigned int i = 0; i < ARRAY_SIZE(regs->fpr); ++i) {
+		if (size > i * sizeof(regs->fpr[i])) {
+			if (i)
+				fputs(", ", stdout);
+			PRINT_VAL_X(regs->fpr[i]);
+		}
+	}
+	fputs("]", stdout);
+	if (size >= offsetofend(TRACEE_REGS_STRUCT, fcc)) {
+		fputs(", ", stdout);
+		PRINT_FIELD_X(*regs, fcc);
+	}
+	if (size >= offsetofend(TRACEE_REGS_STRUCT, fcsr)) {
+		fputs(", ", stdout);
+		PRINT_FIELD_X(*regs, fcsr);
+	}
+
 # endif /*
 	   __i386__ ||
+	   __loongarch__ ||
 	   __powerpc64__ ||
 	   __powerpc__ ||
 	   __x86_64__
-- 
2.38.0

