Index: include/__libunwind_config.h
===================================================================
--- include/__libunwind_config.h
+++ include/__libunwind_config.h
@@ -23,6 +23,7 @@
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__i386__)
@@ -113,6 +114,11 @@
# error "Unsupported MIPS ABI and/or environment"
# endif
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
+# elif defined(__sparc__)
+ #define _LIBUNWIND_TARGET_SPARC 1
+ #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
+ #define _LIBUNWIND_CONTEXT_SIZE 16
+ #define _LIBUNWIND_CURSOR_SIZE 23
# else
# error "Unsupported architecture."
# endif
@@ -126,6 +132,7 @@
# define _LIBUNWIND_TARGET_OR1K 1
# define _LIBUNWIND_TARGET_MIPS_O32 1
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+# define _LIBUNWIND_TARGET_SPARC 1
# define _LIBUNWIND_CONTEXT_SIZE 167
# define _LIBUNWIND_CURSOR_SIZE 179
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
Index: include/libunwind.h
===================================================================
--- include/libunwind.h
+++ include/libunwind.h
@@ -823,4 +823,40 @@
UNW_MIPS_LO = 65,
};
+// SPARC registers
+enum {
+ UNW_SPARC_G0 = 0,
+ UNW_SPARC_G1 = 1,
+ UNW_SPARC_G2 = 2,
+ UNW_SPARC_G3 = 3,
+ UNW_SPARC_G4 = 4,
+ UNW_SPARC_G5 = 5,
+ UNW_SPARC_G6 = 6,
+ UNW_SPARC_G7 = 7,
+ UNW_SPARC_O0 = 8,
+ UNW_SPARC_O1 = 9,
+ UNW_SPARC_O2 = 10,
+ UNW_SPARC_O3 = 11,
+ UNW_SPARC_O4 = 12,
+ UNW_SPARC_O5 = 13,
+ UNW_SPARC_O6 = 14,
+ UNW_SPARC_O7 = 15,
+ UNW_SPARC_L0 = 16,
+ UNW_SPARC_L1 = 17,
+ UNW_SPARC_L2 = 18,
+ UNW_SPARC_L3 = 19,
+ UNW_SPARC_L4 = 20,
+ UNW_SPARC_L5 = 21,
+ UNW_SPARC_L6 = 22,
+ UNW_SPARC_L7 = 23,
+ UNW_SPARC_I0 = 24,
+ UNW_SPARC_I1 = 25,
+ UNW_SPARC_I2 = 26,
+ UNW_SPARC_I3 = 27,
+ UNW_SPARC_I4 = 28,
+ UNW_SPARC_I5 = 29,
+ UNW_SPARC_I6 = 30,
+ UNW_SPARC_I7 = 31,
+};
+
#endif
Index: src/DwarfInstructions.hpp
===================================================================
--- src/DwarfInstructions.hpp
+++ src/DwarfInstructions.hpp
@@ -159,7 +159,7 @@
&cieInfo) == NULL) {
PrologInfo prolog;
if (CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
- &prolog)) {
+ R::getArch(), &prolog)) {
// get pointer to cfa (architecture specific)
pint_t cfa = getCFA(addressSpace, prolog, registers);
@@ -204,7 +204,8 @@
// return address needs to be authenticated before the return address is
// restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures.
- if (prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
+ if ((R::getArch() == REGISTERS_ARM64) &&
+ prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING;
#else
@@ -223,6 +224,16 @@
}
#endif
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ if (R::getArch() == REGISTERS_SPARC) {
+ // Skip call site instruction and delay slot
+ returnAddress += 8;
+ // Skip unimp instruction if function returns a struct
+ if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
+ returnAddress += 4;
+ }
+#endif
+
// Return address is address after call site instruction, so setting IP to
// that does simualates a return.
newRegisters.setIP(returnAddress);
Index: src/DwarfParser.hpp
===================================================================
--- src/DwarfParser.hpp
+++ src/DwarfParser.hpp
@@ -20,6 +20,7 @@
#include "libunwind.h"
#include "dwarf2.h"
+#include "Registers.hpp"
#include "config.h"
@@ -106,7 +107,7 @@
FDE_Info *fdeInfo, CIE_Info *cieInfo);
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
- PrologInfo *results);
+ int arch, PrologInfo *results);
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
@@ -114,7 +115,7 @@
static bool parseInstructions(A &addressSpace, pint_t instructions,
pint_t instructionsEnd, const CIE_Info &cieInfo,
pint_t pcoffset,
- PrologInfoStackEntry *&rememberStack,
+ PrologInfoStackEntry *&rememberStack, int arch,
PrologInfo *results);
};
@@ -354,7 +355,7 @@
bool CFI_Parser::parseFDEInstructions(A &addressSpace,
const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
- PrologInfo *results) {
+ int arch, PrologInfo *results) {
// clear results
memset(results, '\0', sizeof(PrologInfo));
PrologInfoStackEntry *rememberStack = NULL;
@@ -362,10 +363,11 @@
// parse CIE then FDE instructions
return parseInstructions(addressSpace, cieInfo.cieInstructions,
cieInfo.cieStart + cieInfo.cieLength, cieInfo,
- (pint_t)(-1), rememberStack, results) &&
+ (pint_t)(-1), rememberStack, arch, results) &&
parseInstructions(addressSpace, fdeInfo.fdeInstructions,
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
- upToPC - fdeInfo.pcStart, rememberStack, results);
+ upToPC - fdeInfo.pcStart, rememberStack, arch,
+ results);
}
/// "run" the DWARF instructions
@@ -374,7 +376,7 @@
pint_t instructionsEnd,
const CIE_Info &cieInfo, pint_t pcoffset,
PrologInfoStackEntry *&rememberStack,
- PrologInfo *results) {
+ int arch, PrologInfo *results) {
pint_t p = instructions;
pint_t codeOffset = 0;
PrologInfo initialState = *results;
@@ -678,11 +680,40 @@
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
break;
-#if defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
+ // The same constant is used to represent different instructions on
+ // AArch64 (negate_ra_state) and SPARC (window_save).
+ static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
+ "uses the same constant");
case DW_CFA_AARCH64_negate_ra_state:
- results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
+ switch (arch) {
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ case REGISTERS_ARM64:
+ results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
+ break;
+#endif
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ // case DW_CFA_GNU_window_save:
+ case REGISTERS_SPARC:
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
+ for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
+ results->savedRegisters[reg].location = kRegisterInRegister;
+ results->savedRegisters[reg].value =
+ ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0;
+ }
+
+ for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value =
+ ((int64_t)reg - UNW_SPARC_L0) * 4;
+ }
+ break;
+#endif
+ }
break;
+#else
+ (void)arch;
#endif
default:
Index: src/Registers.hpp
===================================================================
--- src/Registers.hpp
+++ src/Registers.hpp
@@ -24,6 +24,18 @@
// For emulating 128-bit registers
struct v128 { uint32_t vec[4]; };
+enum {
+ REGISTERS_X86,
+ REGISTERS_X86_64,
+ REGISTERS_PPC,
+ REGISTERS_PPC64,
+ REGISTERS_ARM64,
+ REGISTERS_ARM,
+ REGISTERS_OR1K,
+ REGISTERS_MIPS_O32,
+ REGISTERS_MIPS_NEWABI,
+ REGISTERS_SPARC,
+};
#if defined(_LIBUNWIND_TARGET_I386)
/// Registers_x86 holds the register state of a thread in a 32-bit intel
@@ -45,6 +57,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
+ static int getArch() { return REGISTERS_X86; }
uint32_t getSP() const { return _registers.__esp; }
void setSP(uint32_t value) { _registers.__esp = value; }
@@ -251,6 +264,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
+ static int getArch() { return REGISTERS_X86_64; }
uint64_t getSP() const { return _registers.__rsp; }
void setSP(uint64_t value) { _registers.__rsp = value; }
@@ -564,6 +578,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; }
+ static int getArch() { return REGISTERS_PPC; }
uint64_t getSP() const { return _registers.__r1; }
void setSP(uint32_t value) { _registers.__r1 = value; }
@@ -1129,6 +1144,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; }
+ static int getArch() { return REGISTERS_PPC64; }
uint64_t getSP() const { return _registers.__r1; }
void setSP(uint64_t value) { _registers.__r1 = value; }
@@ -1771,6 +1787,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
+ static int getArch() { return REGISTERS_ARM64; }
uint64_t getSP() const { return _registers.__sp; }
void setSP(uint64_t value) { _registers.__sp = value; }
@@ -2050,6 +2067,7 @@
restoreCoreAndJumpTo();
}
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }
+ static int getArch() { return REGISTERS_ARM; }
uint32_t getSP() const { return _registers.__sp; }
void setSP(uint32_t value) { _registers.__sp = value; }
@@ -2527,6 +2545,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; }
+ static int getArch() { return REGISTERS_OR1K; }
uint64_t getSP() const { return _registers.__r[1]; }
void setSP(uint32_t value) { _registers.__r[1] = value; }
@@ -2723,6 +2742,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+ static int getArch() { return REGISTERS_MIPS_O32; }
uint32_t getSP() const { return _registers.__r[29]; }
void setSP(uint32_t value) { _registers.__r[29] = value; }
@@ -3044,6 +3064,7 @@
static const char *getRegisterName(int num);
void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+ static int getArch() { return REGISTERS_MIPS_NEWABI; }
uint64_t getSP() const { return _registers.__r[29]; }
void setSP(uint64_t value) { _registers.__r[29] = value; }
@@ -3312,6 +3333,191 @@
}
}
#endif // _LIBUNWIND_TARGET_MIPS_NEWABI
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+/// Registers_sparc holds the register state of a thread in a 32-bit Sparc
+/// process.
+class _LIBUNWIND_HIDDEN Registers_sparc {
+public:
+ Registers_sparc();
+ Registers_sparc(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);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; }
+ static int getArch() { return REGISTERS_SPARC; }
+
+ uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6]; }
+ void setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; }
+ uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; }
+ void setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
+
+private:
+ struct sparc_thread_state_t {
+ unsigned int __regs[32];
+ };
+
+ sparc_thread_state_t _registers;
+};
+
+inline Registers_sparc::Registers_sparc(const void *registers) {
+ static_assert((check_fit::does_fit),
+ "sparc registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast(registers),
+ sizeof(_registers));
+}
+
+inline Registers_sparc::Registers_sparc() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_sparc::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_SPARC_I7)
+ return true;
+ return false;
+}
+
+inline uint32_t Registers_sparc::getRegister(int regNum) const {
+ if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) {
+ return _registers.__regs[regNum];
+ }
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__regs[UNW_SPARC_O7];
+ case UNW_REG_SP:
+ return _registers.__regs[UNW_SPARC_O6];
+ }
+ _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline void Registers_sparc::setRegister(int regNum, uint32_t value) {
+ if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) {
+ _registers.__regs[regNum] = value;
+ return;
+ }
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__regs[UNW_SPARC_O7] = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__regs[UNW_SPARC_O6] = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline bool Registers_sparc::validFloatRegister(int) const { return false; }
+
+inline double Registers_sparc::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline void Registers_sparc::setFloatRegister(int, double) {
+ _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline bool Registers_sparc::validVectorRegister(int) const { return false; }
+
+inline v128 Registers_sparc::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline void Registers_sparc::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline const char *Registers_sparc::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "pc";
+ case UNW_SPARC_G0:
+ return "g0";
+ case UNW_SPARC_G1:
+ return "g1";
+ case UNW_SPARC_G2:
+ return "g2";
+ case UNW_SPARC_G3:
+ return "g3";
+ case UNW_SPARC_G4:
+ return "g4";
+ case UNW_SPARC_G5:
+ return "g5";
+ case UNW_SPARC_G6:
+ return "g6";
+ case UNW_SPARC_G7:
+ return "g7";
+ case UNW_SPARC_O0:
+ return "o0";
+ case UNW_SPARC_O1:
+ return "o1";
+ case UNW_SPARC_O2:
+ return "o2";
+ case UNW_SPARC_O3:
+ return "o3";
+ case UNW_SPARC_O4:
+ return "o4";
+ case UNW_SPARC_O5:
+ return "o5";
+ case UNW_REG_SP:
+ case UNW_SPARC_O6:
+ return "sp";
+ case UNW_SPARC_O7:
+ return "o7";
+ case UNW_SPARC_L0:
+ return "l0";
+ case UNW_SPARC_L1:
+ return "l1";
+ case UNW_SPARC_L2:
+ return "l2";
+ case UNW_SPARC_L3:
+ return "l3";
+ case UNW_SPARC_L4:
+ return "l4";
+ case UNW_SPARC_L5:
+ return "l5";
+ case UNW_SPARC_L6:
+ return "l6";
+ case UNW_SPARC_L7:
+ return "l7";
+ case UNW_SPARC_I0:
+ return "i0";
+ case UNW_SPARC_I1:
+ return "i1";
+ case UNW_SPARC_I2:
+ return "i2";
+ case UNW_SPARC_I3:
+ return "i3";
+ case UNW_SPARC_I4:
+ return "i4";
+ case UNW_SPARC_I5:
+ return "i5";
+ case UNW_SPARC_I6:
+ return "fp";
+ case UNW_SPARC_I7:
+ return "i7";
+ default:
+ return "unknown register";
+ }
+}
+#endif // _LIBUNWIND_TARGET_SPARC
+
} // namespace libunwind
#endif // __REGISTERS_HPP__
Index: src/UnwindCursor.hpp
===================================================================
--- src/UnwindCursor.hpp
+++ src/UnwindCursor.hpp
@@ -981,6 +981,10 @@
}
#endif
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
+#endif
+
bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
R dummy;
return compactSaysUseDwarf(dummy, offset);
@@ -1042,6 +1046,11 @@
return true;
}
#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
+#endif
+
#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -1103,6 +1112,11 @@
return 0;
}
#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
+#endif
+
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
@@ -1443,7 +1457,7 @@
if (foundFDE) {
typename CFI_Parser::PrologInfo prolog;
if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
- &prolog)) {
+ R::getArch(), &prolog)) {
// Save off parsed FDE info
_info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd;
@@ -1858,7 +1872,7 @@
if (msg == NULL) {
typename CFI_Parser::PrologInfo prolog;
if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
- pc, &prolog)) {
+ pc, R::getArch(), &prolog)) {
// save off parsed FDE info
_info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd;
@@ -1887,8 +1901,8 @@
// Double check this FDE is for a function that includes the pc.
if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
typename CFI_Parser::PrologInfo prolog;
- if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo,
- cieInfo, pc, &prolog)) {
+ if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
+ pc, R::getArch(), &prolog)) {
// save off parsed FDE info
_info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd;
Index: src/UnwindRegistersRestore.S
===================================================================
--- src/UnwindRegistersRestore.S
+++ src/UnwindRegistersRestore.S
@@ -1000,6 +1000,28 @@
ld $4, (8 * 4)($4)
.set pop
+#elif defined(__sparc__)
+
+//
+// void libunwind::Registers_sparc_o32::jumpto()
+//
+// On entry:
+// thread_state pointer is in o0
+//
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
+ ta 3
+ ldd [%o0 + 64], %l0
+ ldd [%o0 + 72], %l2
+ ldd [%o0 + 80], %l4
+ ldd [%o0 + 88], %l6
+ ldd [%o0 + 96], %i0
+ ldd [%o0 + 104], %i2
+ ldd [%o0 + 112], %i4
+ ldd [%o0 + 120], %i6
+ ld [%o0 + 60], %o7
+ jmp %o7
+ nop
+
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
Index: src/UnwindRegistersSave.S
===================================================================
--- src/UnwindRegistersSave.S
+++ src/UnwindRegistersSave.S
@@ -942,9 +942,37 @@
l.sw 128(r3), r9
# zero epcr
l.sw 132(r3), r0
-#endif
+#elif defined(__sparc__)
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in o0
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ ta 3
+ add %o7, 8, %o7
+ std %g0, [%o0 + 0]
+ std %g2, [%o0 + 8]
+ std %g4, [%o0 + 16]
+ std %g6, [%o0 + 24]
+ std %o0, [%o0 + 32]
+ std %o2, [%o0 + 40]
+ std %o4, [%o0 + 48]
+ std %o6, [%o0 + 56]
+ std %l0, [%o0 + 64]
+ std %l2, [%o0 + 72]
+ std %l4, [%o0 + 80]
+ std %l6, [%o0 + 88]
+ std %i0, [%o0 + 96]
+ std %i2, [%o0 + 104]
+ std %i4, [%o0 + 112]
+ std %i6, [%o0 + 120]
+ jmp %o7
+ clr %o0 // return UNW_ESUCCESS
+#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE
-
Index: src/assembly.h
===================================================================
--- src/assembly.h
+++ src/assembly.h
@@ -85,6 +85,8 @@
#define NO_EXEC_STACK_DIRECTIVE
+#elif defined(__sparc__)
+
#else
#error Unsupported target
Index: src/libunwind.cpp
===================================================================
--- src/libunwind.cpp
+++ src/libunwind.cpp
@@ -67,6 +67,8 @@
# define REGISTER_KIND Registers_mips_newabi
#elif defined(__mips__)
# warning The MIPS architecture is not supported with this ABI and environment!
+#elif defined(__sparc__)
+# define REGISTER_KIND Registers_sparc
#else
# error Architecture not supported
#endif