Index: include/__libunwind_config.h =================================================================== --- include/__libunwind_config.h +++ include/__libunwind_config.h @@ -51,6 +51,16 @@ # define _LIBUNWIND_CONTEXT_SIZE 16 # define _LIBUNWIND_CURSOR_SIZE 28 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 32 +# elif defined(__mips_o32) +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# define _LIBUNWIND_CONTEXT_SIZE 17 +# define _LIBUNWIND_CURSOR_SIZE 28 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 32 +# elif defined(__mips_n64) +# define _LIBUNWIND_TARGET_MIPS_N64 1 +# define _LIBUNWIND_CONTEXT_SIZE 33 +# define _LIBUNWIND_CURSOR_SIZE 45 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 32 # else # error "Unsupported architecture." # endif @@ -61,6 +71,8 @@ # define _LIBUNWIND_TARGET_AARCH64 1 # define _LIBUNWIND_TARGET_ARM 1 # define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# define _LIBUNWIND_TARGET_MIPS_N64 1 # define _LIBUNWIND_CONTEXT_SIZE 128 # define _LIBUNWIND_CURSOR_SIZE 140 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 120 Index: include/libunwind.h =================================================================== --- include/libunwind.h +++ include/libunwind.h @@ -547,4 +547,40 @@ UNW_OR1K_R31 = 31, }; +// MIPS registers +enum { + UNW_MIPS_R0 = 0, + UNW_MIPS_R1 = 1, + UNW_MIPS_R2 = 2, + UNW_MIPS_R3 = 3, + UNW_MIPS_R4 = 4, + UNW_MIPS_R5 = 5, + UNW_MIPS_R6 = 6, + UNW_MIPS_R7 = 7, + UNW_MIPS_R8 = 8, + UNW_MIPS_R9 = 9, + UNW_MIPS_R10 = 10, + UNW_MIPS_R11 = 11, + UNW_MIPS_R12 = 12, + UNW_MIPS_R13 = 13, + UNW_MIPS_R14 = 14, + UNW_MIPS_R15 = 15, + UNW_MIPS_R16 = 16, + UNW_MIPS_R17 = 17, + UNW_MIPS_R18 = 18, + UNW_MIPS_R19 = 19, + UNW_MIPS_R20 = 20, + UNW_MIPS_R21 = 21, + UNW_MIPS_R22 = 22, + UNW_MIPS_R23 = 23, + UNW_MIPS_R24 = 24, + UNW_MIPS_R25 = 25, + UNW_MIPS_R26 = 26, + UNW_MIPS_R27 = 27, + UNW_MIPS_R28 = 28, + UNW_MIPS_R29 = 29, + UNW_MIPS_R30 = 30, + UNW_MIPS_R31 = 31, +}; + #endif Index: src/Registers.hpp =================================================================== --- src/Registers.hpp +++ src/Registers.hpp @@ -1980,6 +1980,378 @@ } #endif // _LIBUNWIND_TARGET_OR1K + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) +/// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS +/// process. +class _LIBUNWIND_HIDDEN Registers_mips_o32 { +public: + Registers_mips_o32(); + Registers_mips_o32(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 31; } + + uint32_t getSP() const { return _registers.__r[29]; } + void setSP(uint32_t value) { _registers.__r[29] = value; } + uint32_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + +private: + struct mips_o32_thread_state_t { + uint32_t __r[32]; + uint32_t __pc; + }; + + mips_o32_thread_state_t _registers; +}; + +inline Registers_mips_o32::Registers_mips_o32(const void *registers) { + static_assert((check_fit::does_fit), + "mips_o32 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_o32::Registers_mips_o32() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_o32::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; + // FIXME: Hard float + return false; +} + +inline uint32_t Registers_mips_o32::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline bool Registers_mips_o32::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_mips_o32::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +} + +inline void Registers_mips_o32::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +} + +inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_o32::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline void Registers_mips_o32::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline const char *Registers_mips_o32::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_O32 + +#if defined(_LIBUNWIND_TARGET_MIPS_N64) +/// Registers_mips_n64 holds the register state of a thread in a 64-bit MIPS +/// process. +class _LIBUNWIND_HIDDEN Registers_mips_n64 { +public: + Registers_mips_n64(); + Registers_mips_n64(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); + const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return 31; } + + uint64_t getSP() const { return _registers.__r[29]; } + void setSP(uint64_t value) { _registers.__r[29] = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint64_t value) { _registers.__pc = value; } + +private: + struct mips_n64_thread_state_t { + uint64_t __r[32]; + uint64_t __pc; + }; + + mips_n64_thread_state_t _registers; +}; + +inline Registers_mips_n64::Registers_mips_n64(const void *registers) { + static_assert((check_fit::does_fit), + "mips_n64 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_n64::Registers_mips_n64() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_n64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; + // FIXME: Hard float + return false; +} + +inline uint64_t Registers_mips_n64::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + } + _LIBUNWIND_ABORT("unsupported mips_n64 register"); +} + +inline void Registers_mips_n64::setRegister(int regNum, uint64_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_n64 register"); +} + +inline bool Registers_mips_n64::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_mips_n64::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_n64 float support not implemented"); +} + +inline void Registers_mips_n64::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("mips_n64 float support not implemented"); +} + +inline bool Registers_mips_n64::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_n64::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_n64 vector support not implemented"); +} + +inline void Registers_mips_n64::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_n64 vector support not implemented"); +} + +inline const char *Registers_mips_n64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_N64 } // namespace libunwind #endif // __REGISTERS_HPP__ Index: src/UnwindCursor.hpp =================================================================== --- src/UnwindCursor.hpp +++ src/UnwindCursor.hpp @@ -514,6 +514,18 @@ } #endif +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + int stepWithCompactEncoding(Registers_mips_o32 &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_N64) + int stepWithCompactEncoding(Registers_mips_n64 &) { + return UNW_EINVAL; + } +#endif + bool compactSaysUseDwarf(uint32_t *offset=NULL) const { R dummy; return compactSaysUseDwarf(dummy, offset); @@ -557,6 +569,18 @@ return false; } #endif + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_N64) + bool compactSaysUseDwarf(Registers_mips_n64 &, uint32_t *) const { + return true; + } +#endif #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) @@ -594,6 +618,18 @@ return 0; } #endif + +#if defined (_LIBUNWIND_TARGET_MIPS_O32) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_MIPS_N64) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_n64 &) const { + return 0; + } +#endif #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) Index: src/UnwindRegistersRestore.S =================================================================== --- src/UnwindRegistersRestore.S +++ src/UnwindRegistersRestore.S @@ -489,6 +489,102 @@ l.jr r9 l.nop +#elif defined(__mips_o32) + +// +// void libunwind::Registers_mips_o32::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// + .set noreorder + .set noat +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) + // r0 is zero + lw $1, (4 * 1)($4) + lw $2, (4 * 2)($4) + lw $3, (4 * 3)($4) + // skip a0 for now + lw $5, (4 * 5)($4) + lw $6, (4 * 6)($4) + lw $7, (4 * 7)($4) + lw $8, (4 * 8)($4) + lw $9, (4 * 9)($4) + lw $10, (4 * 10)($4) + lw $11, (4 * 11)($4) + lw $12, (4 * 12)($4) + lw $13, (4 * 13)($4) + lw $14, (4 * 14)($4) + lw $15, (4 * 15)($4) + lw $16, (4 * 16)($4) + lw $17, (4 * 17)($4) + lw $18, (4 * 18)($4) + lw $19, (4 * 19)($4) + lw $20, (4 * 20)($4) + lw $21, (4 * 21)($4) + lw $22, (4 * 22)($4) + lw $23, (4 * 23)($4) + lw $24, (4 * 24)($4) + lw $25, (4 * 25)($4) + lw $26, (4 * 26)($4) + lw $27, (4 * 27)($4) + lw $28, (4 * 28)($4) + lw $29, (4 * 29)($4) + lw $30, (4 * 30)($4) + // load new pc into ra + lw $31, (4 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + lw $4, (4 * 4)($4) + +#elif defined(__mips_n64) + +// +// void libunwind::Registers_mips_n64::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// + .set noreorder + .set noat +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_n646jumptoEv) + // r0 is zero + ld $1, (8 * 1)($4) + ld $2, (8 * 2)($4) + ld $3, (8 * 3)($4) + // skip a0 for now + ld $5, (8 * 5)($4) + ld $6, (8 * 6)($4) + ld $7, (8 * 7)($4) + ld $8, (8 * 8)($4) + ld $9, (8 * 9)($4) + ld $10, (8 * 10)($4) + ld $11, (8 * 11)($4) + ld $12, (8 * 12)($4) + ld $13, (8 * 13)($4) + ld $14, (8 * 14)($4) + ld $15, (8 * 15)($4) + ld $16, (8 * 16)($4) + ld $17, (8 * 17)($4) + ld $18, (8 * 18)($4) + ld $19, (8 * 19)($4) + ld $20, (8 * 20)($4) + ld $21, (8 * 21)($4) + ld $22, (8 * 22)($4) + ld $23, (8 * 23)($4) + ld $24, (8 * 24)($4) + ld $25, (8 * 25)($4) + ld $26, (8 * 26)($4) + ld $27, (8 * 27)($4) + ld $28, (8 * 28)($4) + ld $29, (8 * 29)($4) + ld $30, (8 * 30)($4) + // load new pc into ra + ld $31, (8 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + ld $4, (8 * 4)($4) + #endif NO_EXEC_STACK_DIRECTIVE Index: src/UnwindRegistersSave.S =================================================================== --- src/UnwindRegistersSave.S +++ src/UnwindRegistersSave.S @@ -87,6 +87,68 @@ xorl %eax, %eax # return UNW_ESUCCESS ret +#elif defined(__mips_o32) + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +# Only save registers preserved across calls. +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + .set noreorder + # s0 - s7 + sw $16, (4 * 16)($4) + sw $17, (4 * 17)($4) + sw $18, (4 * 18)($4) + sw $19, (4 * 19)($4) + sw $20, (4 * 20)($4) + sw $21, (4 * 21)($4) + sw $22, (4 * 22)($4) + sw $23, (4 * 23)($4) + # gp + sw $28, (4 * 28)($4) + # sp + sw $29, (4 * 29)($4) + # Store return address to pc + sw $31, (4 * 32)($4) + jr $31 + # fp (in delay slot) + sw $30, (4 * 30)($4) + +#elif defined(__mips_n64) + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +# Only save registers preserved across calls. +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + .set noreorder + # s0 - s7 + sd $16, (8 * 16)($4) + sd $17, (8 * 17)($4) + sd $18, (8 * 18)($4) + sd $19, (8 * 19)($4) + sd $20, (8 * 20)($4) + sd $21, (8 * 21)($4) + sd $22, (8 * 22)($4) + sd $23, (8 * 23)($4) + # gp + sd $28, (8 * 28)($4) + # sp + sd $29, (8 * 29)($4) + # Store return address to pc + sd $31, (8 * 32)($4) + jr $31 + # fp (in delay slot) + sd $30, (8 * 30)($4) + # elif defined(__mips__) # Index: src/config.h =================================================================== --- src/config.h +++ src/config.h @@ -65,7 +65,7 @@ defined(__ppc__) || defined(__ppc64__) || \ (!defined(__APPLE__) && defined(__arm__)) || \ (defined(__arm64__) || defined(__aarch64__)) || \ - (defined(__APPLE__) && defined(__mips__)) + defined(__mips__) #define _LIBUNWIND_BUILD_ZERO_COST_APIS #endif Index: src/libunwind.cpp =================================================================== --- src/libunwind.cpp +++ src/libunwind.cpp @@ -58,6 +58,10 @@ # define REGISTER_KIND Registers_arm #elif defined(__or1k__) # define REGISTER_KIND Registers_or1k +#elif defined(__mips_o32) +# define REGISTER_KIND Registers_mips_o32 +#elif defined(__mips_n64) +# define REGISTER_KIND Registers_mips_n64 #elif defined(__mips__) # warning The MIPS architecture is not supported. #else