[libunwind] add hexagon support

GitOrigin-RevId: 9107594f376e37e99c71881404c686b306f93ad2
diff --git a/include/__libunwind_config.h b/include/__libunwind_config.h
index 4d03bd8..71d77ca 100644
--- a/include/__libunwind_config.h
+++ b/include/__libunwind_config.h
@@ -23,6 +23,7 @@
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K      32
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS      65
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC     31
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON   34
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV     64
 
 #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
@@ -82,6 +83,12 @@
 #  define _LIBUNWIND_CONTEXT_SIZE 16
 #  define _LIBUNWIND_CURSOR_SIZE 24
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
+# elif defined(__hexagon__)
+#  define _LIBUNWIND_TARGET_HEXAGON 1
+// Values here change when : Registers.hpp - hexagon_thread_state_t change
+#  define _LIBUNWIND_CONTEXT_SIZE 18
+#  define _LIBUNWIND_CURSOR_SIZE 24
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON
 # elif defined(__mips__)
 #  if defined(_ABIO32) && _MIPS_SIM == _ABIO32
 #    define _LIBUNWIND_TARGET_MIPS_O32 1
@@ -142,6 +149,7 @@
 # define _LIBUNWIND_TARGET_MIPS_O32 1
 # define _LIBUNWIND_TARGET_MIPS_NEWABI 1
 # define _LIBUNWIND_TARGET_SPARC 1
+# define _LIBUNWIND_TARGET_HEXAGON 1
 # define _LIBUNWIND_TARGET_RISCV 1
 # define _LIBUNWIND_CONTEXT_SIZE 167
 # define _LIBUNWIND_CURSOR_SIZE 179
diff --git a/include/libunwind.h b/include/libunwind.h
index 1a501b8..23ef47f 100644
--- a/include/libunwind.h
+++ b/include/libunwind.h
@@ -832,6 +832,44 @@
   UNW_SPARC_I7 = 31,
 };
 
+// Hexagon register numbers
+enum {
+  UNW_HEXAGON_R0,
+  UNW_HEXAGON_R1,
+  UNW_HEXAGON_R2,
+  UNW_HEXAGON_R3,
+  UNW_HEXAGON_R4,
+  UNW_HEXAGON_R5,
+  UNW_HEXAGON_R6,
+  UNW_HEXAGON_R7,
+  UNW_HEXAGON_R8,
+  UNW_HEXAGON_R9,
+  UNW_HEXAGON_R10,
+  UNW_HEXAGON_R11,
+  UNW_HEXAGON_R12,
+  UNW_HEXAGON_R13,
+  UNW_HEXAGON_R14,
+  UNW_HEXAGON_R15,
+  UNW_HEXAGON_R16,
+  UNW_HEXAGON_R17,
+  UNW_HEXAGON_R18,
+  UNW_HEXAGON_R19,
+  UNW_HEXAGON_R20,
+  UNW_HEXAGON_R21,
+  UNW_HEXAGON_R22,
+  UNW_HEXAGON_R23,
+  UNW_HEXAGON_R24,
+  UNW_HEXAGON_R25,
+  UNW_HEXAGON_R26,
+  UNW_HEXAGON_R27,
+  UNW_HEXAGON_R28,
+  UNW_HEXAGON_R29,
+  UNW_HEXAGON_R30,
+  UNW_HEXAGON_R31,
+  UNW_HEXAGON_P3_0,
+  UNW_HEXAGON_PC,
+};
+
 // RISC-V registers. These match the DWARF register numbers defined by section
 // 4 of the RISC-V ELF psABI specification, which can be found at:
 //
diff --git a/src/Registers.hpp b/src/Registers.hpp
index ffc75ee..26a0fa8 100644
--- a/src/Registers.hpp
+++ b/src/Registers.hpp
@@ -34,6 +34,7 @@
   REGISTERS_MIPS_O32,
   REGISTERS_MIPS_NEWABI,
   REGISTERS_SPARC,
+  REGISTERS_HEXAGON,
   REGISTERS_RISCV,
 };
 
@@ -3528,6 +3529,187 @@
 }
 #endif // _LIBUNWIND_TARGET_SPARC
 
+#if defined(_LIBUNWIND_TARGET_HEXAGON)
+/// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6
+/// process.
+class _LIBUNWIND_HIDDEN Registers_hexagon {
+public:
+  Registers_hexagon();
+  Registers_hexagon(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_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);
+  const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON; }
+  static int  getArch() { return REGISTERS_HEXAGON; }
+
+  uint32_t  getSP() const         { return _registers.__r[UNW_HEXAGON_R29]; }
+  void      setSP(uint32_t value) { _registers.__r[UNW_HEXAGON_R29] = value; }
+  uint32_t  getIP() const         { return _registers.__r[UNW_HEXAGON_PC]; }
+  void      setIP(uint32_t value) { _registers.__r[UNW_HEXAGON_PC] = value; }
+
+private:
+  struct hexagon_thread_state_t {
+    unsigned int __r[35];
+  };
+
+  hexagon_thread_state_t _registers;
+};
+
+inline Registers_hexagon::Registers_hexagon(const void *registers) {
+  static_assert((check_fit<Registers_hexagon, unw_context_t>::does_fit),
+                "hexagon registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_hexagon::Registers_hexagon() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_hexagon::validRegister(int regNum) const {
+  if (regNum <= UNW_HEXAGON_R31)
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_hexagon::getRegister(int regNum) const {
+  if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31)
+    return _registers.__r[regNum - UNW_HEXAGON_R0];
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__r[UNW_HEXAGON_PC];
+  case UNW_REG_SP:
+    return _registers.__r[UNW_HEXAGON_R29];
+  }
+  _LIBUNWIND_ABORT("unsupported hexagon register");
+}
+
+inline void Registers_hexagon::setRegister(int regNum, uint32_t value) {
+  if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31) {
+    _registers.__r[regNum - UNW_HEXAGON_R0] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__r[UNW_HEXAGON_PC] = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__r[UNW_HEXAGON_R29] = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported hexagon register");
+}
+
+inline bool Registers_hexagon::validFloatRegister(int /* regNum */) const {
+  return false;
+}
+
+inline double Registers_hexagon::getFloatRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("hexagon float support not implemented");
+}
+
+inline void Registers_hexagon::setFloatRegister(int /* regNum */,
+                                             double /* value */) {
+  _LIBUNWIND_ABORT("hexagon float support not implemented");
+}
+
+inline bool Registers_hexagon::validVectorRegister(int /* regNum */) const {
+  return false;
+}
+
+inline v128 Registers_hexagon::getVectorRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("hexagon vector support not implemented");
+}
+
+inline void Registers_hexagon::setVectorRegister(int /* regNum */, v128 /* value */) {
+  _LIBUNWIND_ABORT("hexagon vector support not implemented");
+}
+
+inline const char *Registers_hexagon::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_HEXAGON_R0:
+    return "r0";
+  case UNW_HEXAGON_R1:
+    return "r1";
+  case UNW_HEXAGON_R2:
+    return "r2";
+  case UNW_HEXAGON_R3:
+    return "r3";
+  case UNW_HEXAGON_R4:
+    return "r4";
+  case UNW_HEXAGON_R5:
+    return "r5";
+  case UNW_HEXAGON_R6:
+    return "r6";
+  case UNW_HEXAGON_R7:
+    return "r7";
+  case UNW_HEXAGON_R8:
+    return "r8";
+  case UNW_HEXAGON_R9:
+    return "r9";
+  case UNW_HEXAGON_R10:
+    return "r10";
+  case UNW_HEXAGON_R11:
+    return "r11";
+  case UNW_HEXAGON_R12:
+    return "r12";
+  case UNW_HEXAGON_R13:
+    return "r13";
+  case UNW_HEXAGON_R14:
+    return "r14";
+  case UNW_HEXAGON_R15:
+    return "r15";
+  case UNW_HEXAGON_R16:
+    return "r16";
+  case UNW_HEXAGON_R17:
+    return "r17";
+  case UNW_HEXAGON_R18:
+    return "r18";
+  case UNW_HEXAGON_R19:
+    return "r19";
+  case UNW_HEXAGON_R20:
+    return "r20";
+  case UNW_HEXAGON_R21:
+    return "r21";
+  case UNW_HEXAGON_R22:
+    return "r22";
+  case UNW_HEXAGON_R23:
+    return "r23";
+  case UNW_HEXAGON_R24:
+    return "r24";
+  case UNW_HEXAGON_R25:
+    return "r25";
+  case UNW_HEXAGON_R26:
+    return "r26";
+  case UNW_HEXAGON_R27:
+    return "r27";
+  case UNW_HEXAGON_R28:
+    return "r28";
+  case UNW_HEXAGON_R29:
+    return "r29";
+  case UNW_HEXAGON_R30:
+    return "r30";
+  case UNW_HEXAGON_R31:
+    return "r31";
+  default:
+    return "unknown register";
+  }
+
+}
+#endif // _LIBUNWIND_TARGET_HEXAGON
+
+
 #if defined(_LIBUNWIND_TARGET_RISCV)
 /// Registers_riscv holds the register state of a thread in a 64-bit RISC-V
 /// process.
diff --git a/src/UnwindCursor.hpp b/src/UnwindCursor.hpp
index 32d71c2..8200eee 100644
--- a/src/UnwindCursor.hpp
+++ b/src/UnwindCursor.hpp
@@ -1123,6 +1123,12 @@
   }
 #endif
 
+#if defined (_LIBUNWIND_TARGET_HEXAGON)
+  compact_unwind_encoding_t dwarfEncoding(Registers_hexagon &) const {
+    return 0;
+  }
+#endif
+
 #if defined (_LIBUNWIND_TARGET_MIPS_O32)
   compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const {
     return 0;
diff --git a/src/UnwindRegistersRestore.S b/src/UnwindRegistersRestore.S
index 266da5e..9ad5215 100644
--- a/src/UnwindRegistersRestore.S
+++ b/src/UnwindRegistersRestore.S
@@ -808,6 +808,48 @@
   l.jr     r9
    l.nop
 
+#elif defined(__hexagon__)
+# On entry:
+#  thread_state pointer is in r2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv)
+#
+# void libunwind::Registers_hexagon::jumpto()
+#
+  r8 = memw(r0+#32)
+  r9 = memw(r0+#36)
+  r10 = memw(r0+#40)
+  r11 = memw(r0+#44)
+
+  r12 = memw(r0+#48)
+  r13 = memw(r0+#52)
+  r14 = memw(r0+#56)
+  r15 = memw(r0+#60)
+
+  r16 = memw(r0+#64)
+  r17 = memw(r0+#68)
+  r18 = memw(r0+#72)
+  r19 = memw(r0+#76)
+
+  r20 = memw(r0+#80)
+  r21 = memw(r0+#84)
+  r22 = memw(r0+#88)
+  r23 = memw(r0+#92)
+
+  r24 = memw(r0+#96)
+  r25 = memw(r0+#100)
+  r26 = memw(r0+#104)
+  r27 = memw(r0+#108)
+
+  r28 = memw(r0+#112)
+  r29 = memw(r0+#116)
+  r30 = memw(r0+#120)
+  r31 = memw(r0+#132)
+
+  r1 = memw(r0+#128)
+  c4 = r1   // Predicate register
+  r1 = memw(r0+#4)
+  r0 = memw(r0)
+  jumpr r31
 #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
 
 //
diff --git a/src/UnwindRegistersSave.S b/src/UnwindRegistersSave.S
index 5a89d19..9e52c4c 100644
--- a/src/UnwindRegistersSave.S
+++ b/src/UnwindRegistersSave.S
@@ -945,6 +945,52 @@
   # zero epcr
   l.sw     132(r3), r0
 
+#elif defined(__hexagon__)
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in r0
+#
+#define OFFSET(offset) (offset/4)
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  memw(r0+#32) = r8
+  memw(r0+#36) = r9
+  memw(r0+#40) = r10
+  memw(r0+#44) = r11
+
+  memw(r0+#48) = r12
+  memw(r0+#52) = r13
+  memw(r0+#56) = r14
+  memw(r0+#60) = r15
+
+  memw(r0+#64) = r16
+  memw(r0+#68) = r17
+  memw(r0+#72) = r18
+  memw(r0+#76) = r19
+
+  memw(r0+#80) = r20
+  memw(r0+#84) = r21
+  memw(r0+#88) = r22
+  memw(r0+#92) = r23
+
+  memw(r0+#96) = r24
+  memw(r0+#100) = r25
+  memw(r0+#104) = r26
+  memw(r0+#108) = r27
+
+  memw(r0+#112) = r28
+  memw(r0+#116) = r29
+  memw(r0+#120) = r30
+  memw(r0+#124) = r31
+  r1 = c4   // Predicate register
+  memw(r0+#128) = r1
+  r1 = memw(r30)           // *FP == Saved FP
+  r1 = r31
+  memw(r0+#132) = r1
+
+  jumpr r31
+
 #elif defined(__sparc__)
 
 #
diff --git a/src/assembly.h b/src/assembly.h
index 2c1337b..4cf179e 100644
--- a/src/assembly.h
+++ b/src/assembly.h
@@ -75,9 +75,16 @@
 #define EXPORT_SYMBOL(name)
 #define HIDDEN_SYMBOL(name) .hidden name
 #define WEAK_SYMBOL(name) .weak name
+
+#if defined(__hexagon__)
+#define WEAK_ALIAS(name, aliasname) \
+  WEAK_SYMBOL(aliasname) SEPARATOR                                             \
+  .equiv SYMBOL_NAME(aliasname), SYMBOL_NAME(name)
+#else
 #define WEAK_ALIAS(name, aliasname)                                            \
   WEAK_SYMBOL(aliasname) SEPARATOR                                             \
   SYMBOL_NAME(aliasname) = SYMBOL_NAME(name)
+#endif
 
 #if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
     defined(__linux__)
diff --git a/src/config.h b/src/config.h
index bce53c2..842fd82 100644
--- a/src/config.h
+++ b/src/config.h
@@ -104,7 +104,8 @@
     (!defined(__APPLE__) && defined(__arm__)) ||                               \
     defined(__aarch64__) ||                                                    \
     defined(__mips__) ||                                                       \
-    defined(__riscv)
+    defined(__riscv) ||                                                        \
+    defined(__hexagon__)
 #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
 #define _LIBUNWIND_BUILD_ZERO_COST_APIS
 #endif
diff --git a/src/libunwind.cpp b/src/libunwind.cpp
index 1ee58ad..fd079da 100644
--- a/src/libunwind.cpp
+++ b/src/libunwind.cpp
@@ -50,6 +50,8 @@
 # define REGISTER_KIND Registers_arm
 #elif defined(__or1k__)
 # define REGISTER_KIND Registers_or1k
+#elif defined(__hexagon__)
+# define REGISTER_KIND Registers_hexagon
 #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
 # define REGISTER_KIND Registers_mips_o32
 #elif defined(__mips64)