aboutsummaryrefslogtreecommitdiff
path: root/libunwind
diff options
context:
space:
mode:
authorzhanglimin <zhanglimin@loongson.cn>2022-11-15 14:36:30 +0800
committerWeining Lu <luweining@loongson.cn>2022-11-15 14:37:00 +0800
commitc5072695127e767a76973cdbed683215df31fa40 (patch)
tree9b434ff96f27be94b40a59e635c5d548d29bef55 /libunwind
parent25dcca60f48e936d014fb0c9a8d4b3343f3125b3 (diff)
downloadllvm-c5072695127e767a76973cdbed683215df31fa40.zip
llvm-c5072695127e767a76973cdbed683215df31fa40.tar.gz
llvm-c5072695127e767a76973cdbed683215df31fa40.tar.bz2
[libunwind][LoongArch] Add 64-bit LoongArch support
Defines enums for the LoongArch registers. Adds the register class implementation for LoongArch. Adds save and restore context functionality. This only supports 64 bits integer and float-point register implementation. Fix https://github.com/llvm/llvm-project/issues/55398 Reviewed By: SixWeining Differential Revision: https://reviews.llvm.org/D137010
Diffstat (limited to 'libunwind')
-rw-r--r--libunwind/include/__libunwind_config.h12
-rw-r--r--libunwind/include/libunwind.h68
-rw-r--r--libunwind/src/Registers.hpp266
-rw-r--r--libunwind/src/UnwindCursor.hpp16
-rw-r--r--libunwind/src/UnwindRegistersRestore.S82
-rw-r--r--libunwind/src/UnwindRegistersSave.S80
-rw-r--r--libunwind/src/config.h2
-rw-r--r--libunwind/src/libunwind.cpp2
8 files changed, 527 insertions, 1 deletions
diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 5e9de90..f69fe89 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -30,6 +30,7 @@
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE 143
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X 83
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH 64
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__linux__)
@@ -166,6 +167,16 @@
# define _LIBUNWIND_CONTEXT_SIZE 34
# define _LIBUNWIND_CURSOR_SIZE 46
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X
+#elif defined(__loongarch__)
+#define _LIBUNWIND_TARGET_LOONGARCH 1
+#if __loongarch_grlen == 64
+#define _LIBUNWIND_CONTEXT_SIZE 65
+#define _LIBUNWIND_CURSOR_SIZE 77
+#else
+#error "Unsupported LoongArch ABI"
+#endif
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER \
+ _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH
# else
# error "Unsupported architecture."
# endif
@@ -185,6 +196,7 @@
# define _LIBUNWIND_TARGET_RISCV 1
# define _LIBUNWIND_TARGET_VE 1
# define _LIBUNWIND_TARGET_S390X 1
+#define _LIBUNWIND_TARGET_LOONGARCH 1
# define _LIBUNWIND_CONTEXT_SIZE 167
# define _LIBUNWIND_CURSOR_SIZE 179
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index f878b46..8c8cf8f 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -1219,4 +1219,72 @@ enum {
// 68-83 Vector Registers %v16-%v31
};
+// LoongArch registers.
+enum {
+ UNW_LOONGARCH_R0 = 0,
+ UNW_LOONGARCH_R1 = 1,
+ UNW_LOONGARCH_R2 = 2,
+ UNW_LOONGARCH_R3 = 3,
+ UNW_LOONGARCH_R4 = 4,
+ UNW_LOONGARCH_R5 = 5,
+ UNW_LOONGARCH_R6 = 6,
+ UNW_LOONGARCH_R7 = 7,
+ UNW_LOONGARCH_R8 = 8,
+ UNW_LOONGARCH_R9 = 9,
+ UNW_LOONGARCH_R10 = 10,
+ UNW_LOONGARCH_R11 = 11,
+ UNW_LOONGARCH_R12 = 12,
+ UNW_LOONGARCH_R13 = 13,
+ UNW_LOONGARCH_R14 = 14,
+ UNW_LOONGARCH_R15 = 15,
+ UNW_LOONGARCH_R16 = 16,
+ UNW_LOONGARCH_R17 = 17,
+ UNW_LOONGARCH_R18 = 18,
+ UNW_LOONGARCH_R19 = 19,
+ UNW_LOONGARCH_R20 = 20,
+ UNW_LOONGARCH_R21 = 21,
+ UNW_LOONGARCH_R22 = 22,
+ UNW_LOONGARCH_R23 = 23,
+ UNW_LOONGARCH_R24 = 24,
+ UNW_LOONGARCH_R25 = 25,
+ UNW_LOONGARCH_R26 = 26,
+ UNW_LOONGARCH_R27 = 27,
+ UNW_LOONGARCH_R28 = 28,
+ UNW_LOONGARCH_R29 = 29,
+ UNW_LOONGARCH_R30 = 30,
+ UNW_LOONGARCH_R31 = 31,
+ UNW_LOONGARCH_F0 = 32,
+ UNW_LOONGARCH_F1 = 33,
+ UNW_LOONGARCH_F2 = 34,
+ UNW_LOONGARCH_F3 = 35,
+ UNW_LOONGARCH_F4 = 36,
+ UNW_LOONGARCH_F5 = 37,
+ UNW_LOONGARCH_F6 = 38,
+ UNW_LOONGARCH_F7 = 39,
+ UNW_LOONGARCH_F8 = 40,
+ UNW_LOONGARCH_F9 = 41,
+ UNW_LOONGARCH_F10 = 42,
+ UNW_LOONGARCH_F11 = 43,
+ UNW_LOONGARCH_F12 = 44,
+ UNW_LOONGARCH_F13 = 45,
+ UNW_LOONGARCH_F14 = 46,
+ UNW_LOONGARCH_F15 = 47,
+ UNW_LOONGARCH_F16 = 48,
+ UNW_LOONGARCH_F17 = 49,
+ UNW_LOONGARCH_F18 = 50,
+ UNW_LOONGARCH_F19 = 51,
+ UNW_LOONGARCH_F20 = 52,
+ UNW_LOONGARCH_F21 = 53,
+ UNW_LOONGARCH_F22 = 54,
+ UNW_LOONGARCH_F23 = 55,
+ UNW_LOONGARCH_F24 = 56,
+ UNW_LOONGARCH_F25 = 57,
+ UNW_LOONGARCH_F26 = 58,
+ UNW_LOONGARCH_F27 = 59,
+ UNW_LOONGARCH_F28 = 60,
+ UNW_LOONGARCH_F29 = 61,
+ UNW_LOONGARCH_F30 = 62,
+ UNW_LOONGARCH_F31 = 63,
+};
+
#endif
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index e5fde68..ff736ca 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -40,6 +40,7 @@ enum {
REGISTERS_RISCV,
REGISTERS_VE,
REGISTERS_S390X,
+ REGISTERS_LOONGARCH,
};
#if defined(_LIBUNWIND_TARGET_I386)
@@ -5031,6 +5032,271 @@ inline const char *Registers_s390x::getRegisterName(int regNum) {
}
#endif // _LIBUNWIND_TARGET_S390X
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+/// Registers_loongarch holds the register state of a thread in a 64-bit
+/// LoongArch process.
+class _LIBUNWIND_HIDDEN Registers_loongarch {
+public:
+ Registers_loongarch();
+ Registers_loongarch(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static constexpr int lastDwarfRegNum() {
+ return _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH;
+ }
+ static int getArch() { return REGISTERS_LOONGARCH; }
+
+ uint64_t getSP() const { return _registers.__r[3]; }
+ void setSP(uint64_t value) { _registers.__r[3] = value; }
+ uint64_t getIP() const { return _registers.__pc; }
+ void setIP(uint64_t value) { _registers.__pc = value; }
+
+private:
+ struct loongarch_thread_state_t {
+ uint64_t __r[32];
+ uint64_t __pc;
+ };
+
+ loongarch_thread_state_t _registers;
+#if __loongarch_frlen == 64
+ double _floats[32];
+#endif
+};
+
+inline Registers_loongarch::Registers_loongarch(const void *registers) {
+ static_assert((check_fit<Registers_loongarch, unw_context_t>::does_fit),
+ "loongarch registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+ static_assert(sizeof(_registers) == 0x108,
+ "expected float registers to be at offset 264");
+#if __loongarch_frlen == 64
+ memcpy(_floats, static_cast<const uint8_t *>(registers) + sizeof(_registers),
+ sizeof(_floats));
+#endif
+}
+
+inline Registers_loongarch::Registers_loongarch() {
+ memset(&_registers, 0, sizeof(_registers));
+#if __loongarch_frlen == 64
+ memset(&_floats, 0, sizeof(_floats));
+#endif
+}
+
+inline bool Registers_loongarch::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP || regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0 || regNum > UNW_LOONGARCH_F31)
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_loongarch::getRegister(int regNum) const {
+ if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+ return _registers.__r[regNum - UNW_LOONGARCH_R0];
+
+ if (regNum == UNW_REG_IP)
+ return _registers.__pc;
+ if (regNum == UNW_REG_SP)
+ return _registers.__r[3];
+ _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline void Registers_loongarch::setRegister(int regNum, uint64_t value) {
+ if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+ _registers.__r[regNum - UNW_LOONGARCH_R0] = value;
+ else if (regNum == UNW_REG_IP)
+ _registers.__pc = value;
+ else if (regNum == UNW_REG_SP)
+ _registers.__r[3] = value;
+ else
+ _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline const char *Registers_loongarch::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "$pc";
+ case UNW_REG_SP:
+ return "$sp";
+ case UNW_LOONGARCH_R0:
+ return "$r0";
+ case UNW_LOONGARCH_R1:
+ return "$r1";
+ case UNW_LOONGARCH_R2:
+ return "$r2";
+ case UNW_LOONGARCH_R3:
+ return "$r3";
+ case UNW_LOONGARCH_R4:
+ return "$r4";
+ case UNW_LOONGARCH_R5:
+ return "$r5";
+ case UNW_LOONGARCH_R6:
+ return "$r6";
+ case UNW_LOONGARCH_R7:
+ return "$r7";
+ case UNW_LOONGARCH_R8:
+ return "$r8";
+ case UNW_LOONGARCH_R9:
+ return "$r9";
+ case UNW_LOONGARCH_R10:
+ return "$r10";
+ case UNW_LOONGARCH_R11:
+ return "$r11";
+ case UNW_LOONGARCH_R12:
+ return "$r12";
+ case UNW_LOONGARCH_R13:
+ return "$r13";
+ case UNW_LOONGARCH_R14:
+ return "$r14";
+ case UNW_LOONGARCH_R15:
+ return "$r15";
+ case UNW_LOONGARCH_R16:
+ return "$r16";
+ case UNW_LOONGARCH_R17:
+ return "$r17";
+ case UNW_LOONGARCH_R18:
+ return "$r18";
+ case UNW_LOONGARCH_R19:
+ return "$r19";
+ case UNW_LOONGARCH_R20:
+ return "$r20";
+ case UNW_LOONGARCH_R21:
+ return "$r21";
+ case UNW_LOONGARCH_R22:
+ return "$r22";
+ case UNW_LOONGARCH_R23:
+ return "$r23";
+ case UNW_LOONGARCH_R24:
+ return "$r24";
+ case UNW_LOONGARCH_R25:
+ return "$r25";
+ case UNW_LOONGARCH_R26:
+ return "$r26";
+ case UNW_LOONGARCH_R27:
+ return "$r27";
+ case UNW_LOONGARCH_R28:
+ return "$r28";
+ case UNW_LOONGARCH_R29:
+ return "$r29";
+ case UNW_LOONGARCH_R30:
+ return "$r30";
+ case UNW_LOONGARCH_R31:
+ return "$r31";
+ case UNW_LOONGARCH_F0:
+ return "$f0";
+ case UNW_LOONGARCH_F1:
+ return "$f1";
+ case UNW_LOONGARCH_F2:
+ return "$f2";
+ case UNW_LOONGARCH_F3:
+ return "$f3";
+ case UNW_LOONGARCH_F4:
+ return "$f4";
+ case UNW_LOONGARCH_F5:
+ return "$f5";
+ case UNW_LOONGARCH_F6:
+ return "$f6";
+ case UNW_LOONGARCH_F7:
+ return "$f7";
+ case UNW_LOONGARCH_F8:
+ return "$f8";
+ case UNW_LOONGARCH_F9:
+ return "$f9";
+ case UNW_LOONGARCH_F10:
+ return "$f10";
+ case UNW_LOONGARCH_F11:
+ return "$f11";
+ case UNW_LOONGARCH_F12:
+ return "$f12";
+ case UNW_LOONGARCH_F13:
+ return "$f13";
+ case UNW_LOONGARCH_F14:
+ return "$f14";
+ case UNW_LOONGARCH_F15:
+ return "$f15";
+ case UNW_LOONGARCH_F16:
+ return "$f16";
+ case UNW_LOONGARCH_F17:
+ return "$f17";
+ case UNW_LOONGARCH_F18:
+ return "$f18";
+ case UNW_LOONGARCH_F19:
+ return "$f19";
+ case UNW_LOONGARCH_F20:
+ return "$f20";
+ case UNW_LOONGARCH_F21:
+ return "$f21";
+ case UNW_LOONGARCH_F22:
+ return "$f22";
+ case UNW_LOONGARCH_F23:
+ return "$f23";
+ case UNW_LOONGARCH_F24:
+ return "$f24";
+ case UNW_LOONGARCH_F25:
+ return "$f25";
+ case UNW_LOONGARCH_F26:
+ return "$f26";
+ case UNW_LOONGARCH_F27:
+ return "$f27";
+ case UNW_LOONGARCH_F28:
+ return "$f28";
+ case UNW_LOONGARCH_F29:
+ return "$f29";
+ case UNW_LOONGARCH_F30:
+ return "$f30";
+ case UNW_LOONGARCH_F31:
+ return "$f31";
+ default:
+ return "unknown register";
+ }
+}
+
+inline bool Registers_loongarch::validFloatRegister(int regNum) const {
+ if (regNum < UNW_LOONGARCH_F0 || regNum > UNW_LOONGARCH_F31)
+ return false;
+ return true;
+}
+
+inline double Registers_loongarch::getFloatRegister(int regNum) const {
+#if __loongarch_frlen == 64
+ assert(validFloatRegister(regNum));
+ return _floats[regNum - UNW_LOONGARCH_F0];
+#else
+ _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline void Registers_loongarch::setFloatRegister(int regNum, double value) {
+#if __loongarch_frlen == 64
+ assert(validFloatRegister(regNum));
+ _floats[regNum - UNW_LOONGARCH_F0] = value;
+#else
+ _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline bool Registers_loongarch::validVectorRegister(int) const {
+ return false;
+}
+
+inline v128 Registers_loongarch::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+
+inline void Registers_loongarch::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+#endif //_LIBUNWIND_TARGET_LOONGARCH
} // namespace libunwind
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index f118497..0c6cda3 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1064,6 +1064,10 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+ int stepWithCompactEncoding(Registers_loongarch &) { return UNW_EINVAL; }
+#endif
+
#if defined(_LIBUNWIND_TARGET_SPARC)
int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
#endif
@@ -1140,6 +1144,12 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+ bool compactSaysUseDwarf(Registers_loongarch &, uint32_t *) const {
+ return true;
+ }
+#endif
+
#if defined(_LIBUNWIND_TARGET_SPARC)
bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
#endif
@@ -1224,6 +1234,12 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+ compact_unwind_encoding_t dwarfEncoding(Registers_loongarch &) const {
+ return 0;
+ }
+#endif
+
#if defined(_LIBUNWIND_TARGET_SPARC)
compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
#endif
diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index 62f8f82..08f208e 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -1289,6 +1289,88 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
// Return to PSWA (was loaded into %r1 above)
br %r1
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+//
+// void libunwind::Registers_loongarch::jumpto()
+//
+// On entry:
+// thread_state pointer is in $a0($r4)
+//
+ .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
+# if __loongarch_frlen == 64
+ fld.d $f0, $a0, (8 * 33 + 8 * 0)
+ fld.d $f1, $a0, (8 * 33 + 8 * 1)
+ fld.d $f2, $a0, (8 * 33 + 8 * 2)
+ fld.d $f3, $a0, (8 * 33 + 8 * 3)
+ fld.d $f4, $a0, (8 * 33 + 8 * 4)
+ fld.d $f5, $a0, (8 * 33 + 8 * 5)
+ fld.d $f6, $a0, (8 * 33 + 8 * 6)
+ fld.d $f7, $a0, (8 * 33 + 8 * 7)
+ fld.d $f8, $a0, (8 * 33 + 8 * 8)
+ fld.d $f9, $a0, (8 * 33 + 8 * 9)
+ fld.d $f10, $a0, (8 * 33 + 8 * 10)
+ fld.d $f11, $a0, (8 * 33 + 8 * 11)
+ fld.d $f12, $a0, (8 * 33 + 8 * 12)
+ fld.d $f13, $a0, (8 * 33 + 8 * 13)
+ fld.d $f14, $a0, (8 * 33 + 8 * 14)
+ fld.d $f15, $a0, (8 * 33 + 8 * 15)
+ fld.d $f16, $a0, (8 * 33 + 8 * 16)
+ fld.d $f17, $a0, (8 * 33 + 8 * 17)
+ fld.d $f18, $a0, (8 * 33 + 8 * 18)
+ fld.d $f19, $a0, (8 * 33 + 8 * 19)
+ fld.d $f20, $a0, (8 * 33 + 8 * 20)
+ fld.d $f21, $a0, (8 * 33 + 8 * 21)
+ fld.d $f22, $a0, (8 * 33 + 8 * 22)
+ fld.d $f23, $a0, (8 * 33 + 8 * 23)
+ fld.d $f24, $a0, (8 * 33 + 8 * 24)
+ fld.d $f25, $a0, (8 * 33 + 8 * 25)
+ fld.d $f26, $a0, (8 * 33 + 8 * 26)
+ fld.d $f27, $a0, (8 * 33 + 8 * 27)
+ fld.d $f28, $a0, (8 * 33 + 8 * 28)
+ fld.d $f29, $a0, (8 * 33 + 8 * 29)
+ fld.d $f30, $a0, (8 * 33 + 8 * 30)
+ fld.d $f31, $a0, (8 * 33 + 8 * 31)
+# endif
+
+ // $r0 is zero
+ ld.d $r1, $a0, (8 * 1)
+ ld.d $r2, $a0, (8 * 2)
+ ld.d $r3, $a0, (8 * 3)
+ // skip $a0 for now
+ ld.d $r5, $a0, (8 * 5)
+ ld.d $r6, $a0, (8 * 6)
+ ld.d $r7, $a0, (8 * 7)
+ ld.d $r8, $a0, (8 * 8)
+ ld.d $r9, $a0, (8 * 9)
+ ld.d $r10, $a0, (8 * 10)
+ ld.d $r11, $a0, (8 * 11)
+ ld.d $r12, $a0, (8 * 12)
+ ld.d $r13, $a0, (8 * 13)
+ ld.d $r14, $a0, (8 * 14)
+ ld.d $r15, $a0, (8 * 15)
+ ld.d $r16, $a0, (8 * 16)
+ ld.d $r17, $a0, (8 * 17)
+ ld.d $r18, $a0, (8 * 18)
+ ld.d $r19, $a0, (8 * 19)
+ ld.d $r20, $a0, (8 * 20)
+ ld.d $r21, $a0, (8 * 21)
+ ld.d $r22, $a0, (8 * 22)
+ ld.d $r23, $a0, (8 * 23)
+ ld.d $r24, $a0, (8 * 24)
+ ld.d $r25, $a0, (8 * 25)
+ ld.d $r26, $a0, (8 * 26)
+ ld.d $r27, $a0, (8 * 27)
+ ld.d $r28, $a0, (8 * 28)
+ ld.d $r29, $a0, (8 * 29)
+ ld.d $r30, $a0, (8 * 30)
+ ld.d $r31, $a0, (8 * 31)
+ ld.d $r4, $a0, (8 * 4) // restore $a0 last
+ ld.d $r1, $a0, (8 * 32) // load new pc into $ra
+
+ jr $ra
+
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index f57dd63..b3899bf 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -1222,6 +1222,86 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
lghi %r2, 0
br %r14
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in $a0($r4)
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+ st.d $r1, $a0, (8 * 1)
+ st.d $r2, $a0, (8 * 2)
+ st.d $r3, $a0, (8 * 3)
+ st.d $r4, $a0, (8 * 4)
+ st.d $r5, $a0, (8 * 5)
+ st.d $r6, $a0, (8 * 6)
+ st.d $r7, $a0, (8 * 7)
+ st.d $r8, $a0, (8 * 8)
+ st.d $r9, $a0, (8 * 9)
+ st.d $r10, $a0, (8 * 10)
+ st.d $r11, $a0, (8 * 11)
+ st.d $r12, $a0, (8 * 12)
+ st.d $r13, $a0, (8 * 13)
+ st.d $r14, $a0, (8 * 14)
+ st.d $r15, $a0, (8 * 15)
+ st.d $r16, $a0, (8 * 16)
+ st.d $r17, $a0, (8 * 17)
+ st.d $r18, $a0, (8 * 18)
+ st.d $r19, $a0, (8 * 19)
+ st.d $r20, $a0, (8 * 20)
+ st.d $r21, $a0, (8 * 21)
+ st.d $r22, $a0, (8 * 22)
+ st.d $r23, $a0, (8 * 23)
+ st.d $r24, $a0, (8 * 24)
+ st.d $r25, $a0, (8 * 25)
+ st.d $r26, $a0, (8 * 26)
+ st.d $r27, $a0, (8 * 27)
+ st.d $r28, $a0, (8 * 28)
+ st.d $r29, $a0, (8 * 29)
+ st.d $r30, $a0, (8 * 30)
+ st.d $r31, $a0, (8 * 31)
+ st.d $r1, $a0, (8 * 32) // store $ra to pc
+
+# if __loongarch_frlen == 64
+ fst.d $f0, $a0, (8 * 33 + 8 * 0)
+ fst.d $f1, $a0, (8 * 33 + 8 * 1)
+ fst.d $f2, $a0, (8 * 33 + 8 * 2)
+ fst.d $f3, $a0, (8 * 33 + 8 * 3)
+ fst.d $f4, $a0, (8 * 33 + 8 * 4)
+ fst.d $f5, $a0, (8 * 33 + 8 * 5)
+ fst.d $f6, $a0, (8 * 33 + 8 * 6)
+ fst.d $f7, $a0, (8 * 33 + 8 * 7)
+ fst.d $f8, $a0, (8 * 33 + 8 * 8)
+ fst.d $f9, $a0, (8 * 33 + 8 * 9)
+ fst.d $f10, $a0, (8 * 33 + 8 * 10)
+ fst.d $f11, $a0, (8 * 33 + 8 * 11)
+ fst.d $f12, $a0, (8 * 33 + 8 * 12)
+ fst.d $f13, $a0, (8 * 33 + 8 * 13)
+ fst.d $f14, $a0, (8 * 33 + 8 * 14)
+ fst.d $f15, $a0, (8 * 33 + 8 * 15)
+ fst.d $f16, $a0, (8 * 33 + 8 * 16)
+ fst.d $f17, $a0, (8 * 33 + 8 * 17)
+ fst.d $f18, $a0, (8 * 33 + 8 * 18)
+ fst.d $f19, $a0, (8 * 33 + 8 * 19)
+ fst.d $f20, $a0, (8 * 33 + 8 * 20)
+ fst.d $f21, $a0, (8 * 33 + 8 * 21)
+ fst.d $f22, $a0, (8 * 33 + 8 * 22)
+ fst.d $f23, $a0, (8 * 33 + 8 * 23)
+ fst.d $f24, $a0, (8 * 33 + 8 * 24)
+ fst.d $f25, $a0, (8 * 33 + 8 * 25)
+ fst.d $f26, $a0, (8 * 33 + 8 * 26)
+ fst.d $f27, $a0, (8 * 33 + 8 * 27)
+ fst.d $f28, $a0, (8 * 33 + 8 * 28)
+ fst.d $f29, $a0, (8 * 33 + 8 * 29)
+ fst.d $f30, $a0, (8 * 33 + 8 * 30)
+ fst.d $f31, $a0, (8 * 33 + 8 * 31)
+# endif
+
+ move $a0, $zero // UNW_ESUCCESS
+ jr $ra
+
#endif
WEAK_ALIAS(__unw_getcontext, unw_getcontext)
diff --git a/libunwind/src/config.h b/libunwind/src/config.h
index cc41b81..4bbac951 100644
--- a/libunwind/src/config.h
+++ b/libunwind/src/config.h
@@ -115,7 +115,7 @@
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \
(!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) || \
defined(__mips__) || defined(__riscv) || defined(__hexagon__) || \
- defined(__sparc__) || defined(__s390x__)
+ defined(__sparc__) || defined(__s390x__) || defined(__loongarch__)
#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
#define _LIBUNWIND_BUILD_ZERO_COST_APIS
#endif
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 292544d..0faea2b 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -77,6 +77,8 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
# define REGISTER_KIND Registers_ve
#elif defined(__s390x__)
# define REGISTER_KIND Registers_s390x
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+#define REGISTER_KIND Registers_loongarch
#else
# error Architecture not supported
#endif