[Sparc] Add Sparc V8 support

Summary:
Adds the register class implementation for Sparc.
Adds support for DW_CFA_GNU_window_save.
Adds save and restore context functionality.

Adds getArch() function to each Registers_ class to be able to separate
between DW_CFA_AARCH64_negate_ra_state and DW_CFA_GNU_window_save which
are both represented by the same constant.

On Sparc the return address is the address of the call instruction, so
an offset needs to be added when returning to skip the call instruction
and its delay slot. If the function returns a struct it is also necessary
to skip one extra instruction on Sparc V8.

Reviewers: jyknight, mclow.lists, mstorsjo, compnerd

Reviewed By: jyknight, compnerd

Subscribers: jgorbe, mgorny, christof, llvm-commits, fedor.sergeev, JDevlieghere, ldionne, libcxx-commits

Differential Revision: https://reviews.llvm.org/D55763

llvm-svn: 351044
This commit is contained in:
Daniel Cederman 2019-01-14 10:15:20 +00:00
parent 5c1768fc57
commit 17121adfa6
10 changed files with 376 additions and 17 deletions

View File

@ -23,6 +23,7 @@
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
#if defined(_LIBUNWIND_IS_NATIVE_ONLY) #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__i386__) # if defined(__i386__)
@ -113,6 +114,11 @@
# error "Unsupported MIPS ABI and/or environment" # error "Unsupported MIPS ABI and/or environment"
# endif # endif
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS # 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 # else
# error "Unsupported architecture." # error "Unsupported architecture."
# endif # endif
@ -126,6 +132,7 @@
# define _LIBUNWIND_TARGET_OR1K 1 # define _LIBUNWIND_TARGET_OR1K 1
# define _LIBUNWIND_TARGET_MIPS_O32 1 # define _LIBUNWIND_TARGET_MIPS_O32 1
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 # define _LIBUNWIND_TARGET_MIPS_NEWABI 1
# define _LIBUNWIND_TARGET_SPARC 1
# define _LIBUNWIND_CONTEXT_SIZE 167 # define _LIBUNWIND_CONTEXT_SIZE 167
# define _LIBUNWIND_CURSOR_SIZE 179 # define _LIBUNWIND_CURSOR_SIZE 179
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287

View File

@ -823,4 +823,40 @@ enum {
UNW_MIPS_LO = 65, 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 #endif

View File

@ -159,7 +159,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
&cieInfo) == NULL) { &cieInfo) == NULL) {
PrologInfo prolog; PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
&prolog)) { R::getArch(), &prolog)) {
// get pointer to cfa (architecture specific) // get pointer to cfa (architecture specific)
pint_t cfa = getCFA(addressSpace, prolog, registers); pint_t cfa = getCFA(addressSpace, prolog, registers);
@ -204,7 +204,8 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// return address needs to be authenticated before the return address is // return address needs to be authenticated before the return address is
// restored. autia1716 is used instead of autia as autia1716 assembles // restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures. // 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) #if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING; return UNW_ECROSSRASIGNING;
#else #else
@ -223,6 +224,16 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
} }
#endif #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 // Return address is address after call site instruction, so setting IP to
// that does simualates a return. // that does simualates a return.
newRegisters.setIP(returnAddress); newRegisters.setIP(returnAddress);

View File

@ -20,6 +20,7 @@
#include "libunwind.h" #include "libunwind.h"
#include "dwarf2.h" #include "dwarf2.h"
#include "Registers.hpp"
#include "config.h" #include "config.h"
@ -106,7 +107,7 @@ public:
FDE_Info *fdeInfo, CIE_Info *cieInfo); FDE_Info *fdeInfo, CIE_Info *cieInfo);
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC, 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); static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
@ -114,7 +115,7 @@ private:
static bool parseInstructions(A &addressSpace, pint_t instructions, static bool parseInstructions(A &addressSpace, pint_t instructions,
pint_t instructionsEnd, const CIE_Info &cieInfo, pint_t instructionsEnd, const CIE_Info &cieInfo,
pint_t pcoffset, pint_t pcoffset,
PrologInfoStackEntry *&rememberStack, PrologInfoStackEntry *&rememberStack, int arch,
PrologInfo *results); PrologInfo *results);
}; };
@ -354,7 +355,7 @@ template <typename A>
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace, bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
const FDE_Info &fdeInfo, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC, const CIE_Info &cieInfo, pint_t upToPC,
PrologInfo *results) { int arch, PrologInfo *results) {
// clear results // clear results
memset(results, '\0', sizeof(PrologInfo)); memset(results, '\0', sizeof(PrologInfo));
PrologInfoStackEntry *rememberStack = NULL; PrologInfoStackEntry *rememberStack = NULL;
@ -362,10 +363,11 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
// parse CIE then FDE instructions // parse CIE then FDE instructions
return parseInstructions(addressSpace, cieInfo.cieInstructions, return parseInstructions(addressSpace, cieInfo.cieInstructions,
cieInfo.cieStart + cieInfo.cieLength, cieInfo, cieInfo.cieStart + cieInfo.cieLength, cieInfo,
(pint_t)(-1), rememberStack, results) && (pint_t)(-1), rememberStack, arch, results) &&
parseInstructions(addressSpace, fdeInfo.fdeInstructions, parseInstructions(addressSpace, fdeInfo.fdeInstructions,
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
upToPC - fdeInfo.pcStart, rememberStack, results); upToPC - fdeInfo.pcStart, rememberStack, arch,
results);
} }
/// "run" the DWARF instructions /// "run" the DWARF instructions
@ -374,7 +376,7 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
pint_t instructionsEnd, pint_t instructionsEnd,
const CIE_Info &cieInfo, pint_t pcoffset, const CIE_Info &cieInfo, pint_t pcoffset,
PrologInfoStackEntry *&rememberStack, PrologInfoStackEntry *&rememberStack,
PrologInfo *results) { int arch, PrologInfo *results) {
pint_t p = instructions; pint_t p = instructions;
pint_t codeOffset = 0; pint_t codeOffset = 0;
PrologInfo initialState = *results; PrologInfo initialState = *results;
@ -678,12 +680,41 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
break; 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: case DW_CFA_AARCH64_negate_ra_state:
switch (arch) {
#if defined(_LIBUNWIND_TARGET_AARCH64)
case REGISTERS_ARM64:
results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1; results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
break; break;
#endif #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: default:
operand = opcode & 0x3F; operand = opcode & 0x3F;

View File

@ -24,6 +24,18 @@ namespace libunwind {
// For emulating 128-bit registers // For emulating 128-bit registers
struct v128 { uint32_t vec[4]; }; 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) #if defined(_LIBUNWIND_TARGET_I386)
/// Registers_x86 holds the register state of a thread in a 32-bit intel /// Registers_x86 holds the register state of a thread in a 32-bit intel
@ -45,6 +57,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
static int getArch() { return REGISTERS_X86; }
uint32_t getSP() const { return _registers.__esp; } uint32_t getSP() const { return _registers.__esp; }
void setSP(uint32_t value) { _registers.__esp = value; } void setSP(uint32_t value) { _registers.__esp = value; }
@ -251,6 +264,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
static int getArch() { return REGISTERS_X86_64; }
uint64_t getSP() const { return _registers.__rsp; } uint64_t getSP() const { return _registers.__rsp; }
void setSP(uint64_t value) { _registers.__rsp = value; } void setSP(uint64_t value) { _registers.__rsp = value; }
@ -564,6 +578,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; }
static int getArch() { return REGISTERS_PPC; }
uint64_t getSP() const { return _registers.__r1; } uint64_t getSP() const { return _registers.__r1; }
void setSP(uint32_t value) { _registers.__r1 = value; } void setSP(uint32_t value) { _registers.__r1 = value; }
@ -1129,6 +1144,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; }
static int getArch() { return REGISTERS_PPC64; }
uint64_t getSP() const { return _registers.__r1; } uint64_t getSP() const { return _registers.__r1; }
void setSP(uint64_t value) { _registers.__r1 = value; } void setSP(uint64_t value) { _registers.__r1 = value; }
@ -1771,6 +1787,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
static int getArch() { return REGISTERS_ARM64; }
uint64_t getSP() const { return _registers.__sp; } uint64_t getSP() const { return _registers.__sp; }
void setSP(uint64_t value) { _registers.__sp = value; } void setSP(uint64_t value) { _registers.__sp = value; }
@ -2050,6 +2067,7 @@ public:
restoreCoreAndJumpTo(); restoreCoreAndJumpTo();
} }
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }
static int getArch() { return REGISTERS_ARM; }
uint32_t getSP() const { return _registers.__sp; } uint32_t getSP() const { return _registers.__sp; }
void setSP(uint32_t value) { _registers.__sp = value; } void setSP(uint32_t value) { _registers.__sp = value; }
@ -2527,6 +2545,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; }
static int getArch() { return REGISTERS_OR1K; }
uint64_t getSP() const { return _registers.__r[1]; } uint64_t getSP() const { return _registers.__r[1]; }
void setSP(uint32_t value) { _registers.__r[1] = value; } void setSP(uint32_t value) { _registers.__r[1] = value; }
@ -2723,6 +2742,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
static int getArch() { return REGISTERS_MIPS_O32; }
uint32_t getSP() const { return _registers.__r[29]; } uint32_t getSP() const { return _registers.__r[29]; }
void setSP(uint32_t value) { _registers.__r[29] = value; } void setSP(uint32_t value) { _registers.__r[29] = value; }
@ -3044,6 +3064,7 @@ public:
static const char *getRegisterName(int num); static const char *getRegisterName(int num);
void jumpto(); void jumpto();
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
static int getArch() { return REGISTERS_MIPS_NEWABI; }
uint64_t getSP() const { return _registers.__r[29]; } uint64_t getSP() const { return _registers.__r[29]; }
void setSP(uint64_t value) { _registers.__r[29] = value; } void setSP(uint64_t value) { _registers.__r[29] = value; }
@ -3312,6 +3333,191 @@ inline const char *Registers_mips_newabi::getRegisterName(int regNum) {
} }
} }
#endif // _LIBUNWIND_TARGET_MIPS_NEWABI #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<Registers_sparc, unw_context_t>::does_fit),
"sparc registers do not fit into unw_context_t");
memcpy(&_registers, static_cast<const uint8_t *>(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 } // namespace libunwind
#endif // __REGISTERS_HPP__ #endif // __REGISTERS_HPP__

View File

@ -981,6 +981,10 @@ private:
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_SPARC)
int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
#endif
bool compactSaysUseDwarf(uint32_t *offset=NULL) const { bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
R dummy; R dummy;
return compactSaysUseDwarf(dummy, offset); return compactSaysUseDwarf(dummy, offset);
@ -1042,6 +1046,11 @@ private:
return true; return true;
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_SPARC)
bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
#endif
#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@ -1103,6 +1112,11 @@ private:
return 0; return 0;
} }
#endif #endif
#if defined(_LIBUNWIND_TARGET_SPARC)
compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
#endif
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
@ -1443,7 +1457,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
if (foundFDE) { if (foundFDE) {
typename CFI_Parser<A>::PrologInfo prolog; typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
&prolog)) { R::getArch(), &prolog)) {
// Save off parsed FDE info // Save off parsed FDE info
_info.start_ip = fdeInfo.pcStart; _info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd; _info.end_ip = fdeInfo.pcEnd;
@ -1858,7 +1872,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
if (msg == NULL) { if (msg == NULL) {
typename CFI_Parser<A>::PrologInfo prolog; typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
pc, &prolog)) { pc, R::getArch(), &prolog)) {
// save off parsed FDE info // save off parsed FDE info
_info.start_ip = fdeInfo.pcStart; _info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd; _info.end_ip = fdeInfo.pcEnd;
@ -1887,8 +1901,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// Double check this FDE is for a function that includes the pc. // Double check this FDE is for a function that includes the pc.
if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
typename CFI_Parser<A>::PrologInfo prolog; typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
cieInfo, pc, &prolog)) { pc, R::getArch(), &prolog)) {
// save off parsed FDE info // save off parsed FDE info
_info.start_ip = fdeInfo.pcStart; _info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd; _info.end_ip = fdeInfo.pcEnd;

View File

@ -1000,6 +1000,28 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
ld $4, (8 * 4)($4) ld $4, (8 * 4)($4)
.set pop .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
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */

View File

@ -942,9 +942,37 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
l.sw 128(r3), r9 l.sw 128(r3), r9
# zero epcr # zero epcr
l.sw 132(r3), r0 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__) */ #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE NO_EXEC_STACK_DIRECTIVE

View File

@ -85,6 +85,8 @@
#define NO_EXEC_STACK_DIRECTIVE #define NO_EXEC_STACK_DIRECTIVE
#elif defined(__sparc__)
#else #else
#error Unsupported target #error Unsupported target

View File

@ -67,6 +67,8 @@ _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
# define REGISTER_KIND Registers_mips_newabi # define REGISTER_KIND Registers_mips_newabi
#elif defined(__mips__) #elif defined(__mips__)
# warning The MIPS architecture is not supported with this ABI and environment! # warning The MIPS architecture is not supported with this ABI and environment!
#elif defined(__sparc__)
# define REGISTER_KIND Registers_sparc
#else #else
# error Architecture not supported # error Architecture not supported
#endif #endif