/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
 *
 * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 */
 
//
//	C++ interface to lower levels of libuwind 
//

#ifndef __REGISTERS_HPP__
#define __REGISTERS_HPP__

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <mach-o/loader.h>
#include <mach-o/getsect.h>
#include <mach/i386/thread_status.h>

#include "libunwind.h"
#include "InternalMacros.h"

namespace libunwind {


///
/// Registers_x86 holds the register state of a thread in a 32-bit intel process.  
///
class Registers_x86
{
public:	
					Registers_x86();
					Registers_x86(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 { return false; }
	double			getFloatRegister(int num) const;
	void			setFloatRegister(int num, double value); 
	bool			validVectorRegister(int num) const { return false; }
	v128			getVectorRegister(int num) const;
	void			setVectorRegister(int num, v128 value);
	const char*		getRegisterName(int num);
	void			jumpto();
	
	uint32_t		getSP() const			{ return fRegisters.__esp; }
	void			setSP(uint32_t value)	{ fRegisters.__esp = value; }
	uint32_t		getIP()	const			{ return fRegisters.__eip; }
	void			setIP(uint32_t value)	{ fRegisters.__eip = value; }
	uint32_t		getEBP() const			{ return fRegisters.__ebp; }
	void			setEBP(uint32_t value)	{ fRegisters.__ebp = value; }
	uint32_t		getEBX() const			{ return fRegisters.__ebx; }
	void			setEBX(uint32_t value)	{ fRegisters.__ebx = value; }
	uint32_t		getECX() const			{ return fRegisters.__ecx; }
	void			setECX(uint32_t value)	{ fRegisters.__ecx = value; }
	uint32_t		getEDX() const			{ return fRegisters.__edx; }
	void			setEDX(uint32_t value)	{ fRegisters.__edx = value; }
	uint32_t		getESI() const			{ return fRegisters.__esi; }
	void			setESI(uint32_t value)	{ fRegisters.__esi = value; }
	uint32_t		getEDI() const			{ return fRegisters.__edi; }
	void			setEDI(uint32_t value)	{ fRegisters.__edi = value; }
	
private:
	i386_thread_state_t  fRegisters;
};

inline Registers_x86::Registers_x86(const void* registers)
{
	COMPILE_TIME_ASSERT( sizeof(Registers_x86) < sizeof(unw_context_t) );
	fRegisters = *((i386_thread_state_t*)registers); 
}

inline Registers_x86::Registers_x86()
{
	bzero(&fRegisters, sizeof(fRegisters)); 
}


inline bool Registers_x86::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 > 7 )
		return false;
	return true;
}

inline uint32_t Registers_x86::getRegister(int regNum) const
{
	switch ( regNum ) {
		case UNW_REG_IP:
			return fRegisters.__eip;
		case UNW_REG_SP:
			return fRegisters.__esp;
		case UNW_X86_EAX:
			return fRegisters.__eax;
		case UNW_X86_ECX:
			return fRegisters.__ecx;
		case UNW_X86_EDX:
			return fRegisters.__edx;
		case UNW_X86_EBX:
			return fRegisters.__ebx;
		case UNW_X86_EBP:
			return fRegisters.__ebp;
		case UNW_X86_ESP:
			return fRegisters.__esp;
		case UNW_X86_ESI:
			return fRegisters.__esi;
		case UNW_X86_EDI:
			return fRegisters.__edi;
	}
	ABORT("unsupported x86 register");
}

inline void Registers_x86::setRegister(int regNum, uint32_t value)
{
	switch ( regNum ) {
		case UNW_REG_IP:
			fRegisters.__eip = value;
			return;
		case UNW_REG_SP:
			fRegisters.__esp = value;
			return;
		case UNW_X86_EAX:
			fRegisters.__eax = value;
			return;
		case UNW_X86_ECX:
			fRegisters.__ecx = value;
			return;
		case UNW_X86_EDX:
			fRegisters.__edx = value;
			return;
		case UNW_X86_EBX:
			fRegisters.__ebx = value;
			return;
		case UNW_X86_EBP:
			fRegisters.__ebp = value;
			return;
		case UNW_X86_ESP:
			fRegisters.__esp = value;
			return;
		case UNW_X86_ESI:
			fRegisters.__esi = value;
			return;
		case UNW_X86_EDI:
			fRegisters.__edi = value;
			return;
	}
	ABORT("unsupported x86 register");
}

inline const char* Registers_x86::getRegisterName(int regNum)
{
	switch ( regNum ) {
		case UNW_REG_IP:
			return "ip";
		case UNW_REG_SP:
			return "esp";
		case UNW_X86_EAX:
			return "eax";
		case UNW_X86_ECX:
			return "ecx";
		case UNW_X86_EDX:
			return "edx";
		case UNW_X86_EBX:
			return "ebx";
		case UNW_X86_EBP:
			return "ebp";
		case UNW_X86_ESP:
			return "esp";
		case UNW_X86_ESI:
			return "esi";
		case UNW_X86_EDI:
			return "edi";
		default:
			return "unknown register";
	}
}

inline double Registers_x86::getFloatRegister(int num) const
{
	ABORT("no x86 float registers");
}

inline void Registers_x86::setFloatRegister(int num, double value)
{
	ABORT("no x86 float registers");
}

inline v128 Registers_x86::getVectorRegister(int num) const
{
	ABORT("no x86 vector registers");
}

inline void Registers_x86::setVectorRegister(int num, v128 value)
{
	ABORT("no x86 vector registers");
}




///
/// Registers_x86_64  holds the register state of a thread in a 64-bit intel process.  
///
class Registers_x86_64
{
public:	
					Registers_x86_64();
					Registers_x86_64(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{ return false; }
	double			getFloatRegister(int num) const;
	void			setFloatRegister(int num, double value);
	bool			validVectorRegister(int num) const { return false; }
	v128			getVectorRegister(int num) const;
	void			setVectorRegister(int num, v128 value);
	const char*		getRegisterName(int num);
	void			jumpto();
	uint64_t		getSP()	const			{ return fRegisters.__rsp; }
	void			setSP(uint64_t value)	{ fRegisters.__rsp = value; }
	uint64_t		getIP()	const			{ return fRegisters.__rip; }
	void			setIP(uint64_t value)	{ fRegisters.__rip = value; }
	uint64_t		getRBP() const			{ return fRegisters.__rbp; }
	void			setRBP(uint64_t value)	{ fRegisters.__rbp = value; }
	uint64_t		getRBX() const			{ return fRegisters.__rbx; }
	void			setRBX(uint64_t value)	{ fRegisters.__rbx = value; }
	uint64_t		getR12() const			{ return fRegisters.__r12; }
	void			setR12(uint64_t value)	{ fRegisters.__r12 = value; }
	uint64_t		getR13() const			{ return fRegisters.__r13; }
	void			setR13(uint64_t value)	{ fRegisters.__r13 = value; }
	uint64_t		getR14() const			{ return fRegisters.__r14; }
	void			setR14(uint64_t value)	{ fRegisters.__r14 = value; }
	uint64_t		getR15() const			{ return fRegisters.__r15; }
	void			setR15(uint64_t value)	{ fRegisters.__r15 = value; }
private:
	x86_thread_state64_t fRegisters;
};

inline Registers_x86_64::Registers_x86_64(const void* registers)
{
	COMPILE_TIME_ASSERT( sizeof(Registers_x86_64) < sizeof(unw_context_t) );
	fRegisters = *((x86_thread_state64_t*)registers); 
}

inline Registers_x86_64::Registers_x86_64()
{
	bzero(&fRegisters, sizeof(fRegisters)); 
}


inline bool Registers_x86_64::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 > 15 )
		return false;
	return true;
}

inline uint64_t Registers_x86_64::getRegister(int regNum) const
{
	switch ( regNum ) {
		case UNW_REG_IP:
			return fRegisters.__rip;
		case UNW_REG_SP:
			return fRegisters.__rsp;
		case UNW_X86_64_RAX:
			return fRegisters.__rax;
		case UNW_X86_64_RDX:
			return fRegisters.__rdx;
		case UNW_X86_64_RCX:
			return fRegisters.__rcx;
		case UNW_X86_64_RBX:
			return fRegisters.__rbx;
		case UNW_X86_64_RSI:
			return fRegisters.__rsi;
		case UNW_X86_64_RDI:
			return fRegisters.__rdi;
		case UNW_X86_64_RBP:
			return fRegisters.__rbp;
		case UNW_X86_64_RSP:
			return fRegisters.__rsp;
		case UNW_X86_64_R8:
			return fRegisters.__r8;
		case UNW_X86_64_R9:
			return fRegisters.__r9;
		case UNW_X86_64_R10:
			return fRegisters.__r10;
		case UNW_X86_64_R11:
			return fRegisters.__r11;
		case UNW_X86_64_R12:
			return fRegisters.__r12;
		case UNW_X86_64_R13:
			return fRegisters.__r13;
		case UNW_X86_64_R14:
			return fRegisters.__r14;
		case UNW_X86_64_R15:
			return fRegisters.__r15;
	}
	ABORT("unsupported x86_64 register");
}

inline void Registers_x86_64::setRegister(int regNum, uint64_t value)
{
	switch ( regNum ) {
		case UNW_REG_IP:
			fRegisters.__rip = value;
			return;
		case UNW_REG_SP:
			fRegisters.__rsp = value;
			return;
		case UNW_X86_64_RAX:
			fRegisters.__rax = value;
			return;
		case UNW_X86_64_RDX:
			fRegisters.__rdx = value;
			return;
		case UNW_X86_64_RCX:
			fRegisters.__rcx = value;
			return;
		case UNW_X86_64_RBX:
			fRegisters.__rbx = value;
			return;
		case UNW_X86_64_RSI:
			fRegisters.__rsi = value;
			return;
		case UNW_X86_64_RDI:
			fRegisters.__rdi = value;
			return;
		case UNW_X86_64_RBP:
			fRegisters.__rbp = value;
			return;
		case UNW_X86_64_RSP:
			fRegisters.__rsp = value;
			return;
		case UNW_X86_64_R8:
			fRegisters.__r8 = value;
			return;
		case UNW_X86_64_R9:
			fRegisters.__r9 = value;
			return;
		case UNW_X86_64_R10:
			fRegisters.__r10 = value;
			return;
		case UNW_X86_64_R11:
			fRegisters.__r11 = value;
			return;
		case UNW_X86_64_R12:
			fRegisters.__r12 = value;
			return;
		case UNW_X86_64_R13:
			fRegisters.__r13 = value;
			return;
		case UNW_X86_64_R14:
			fRegisters.__r14 = value;
			return;
		case UNW_X86_64_R15:
			fRegisters.__r15 = value;
			return;
	}
	ABORT("unsupported x86_64 register");
}

inline const char* Registers_x86_64::getRegisterName(int regNum)
{
	switch ( regNum ) {
		case UNW_REG_IP:
			return "rip";
		case UNW_REG_SP:
			return "rsp";
		case UNW_X86_64_RAX:
			return "rax";
		case UNW_X86_64_RDX:
			return "rdx";
		case UNW_X86_64_RCX:
			return "rcx";
		case UNW_X86_64_RBX:
			return "rbx";
		case UNW_X86_64_RSI:
			return "rsi";
		case UNW_X86_64_RDI:
			return "rdi";
		case UNW_X86_64_RBP:
			return "rbp";
		case UNW_X86_64_RSP:
			return "rsp";
		case UNW_X86_64_R8:
			return "r8";
		case UNW_X86_64_R9:
			return "r9";
		case UNW_X86_64_R10:
			return "r10";
		case UNW_X86_64_R11:
			return "r11";
		case UNW_X86_64_R12:
			return "r12";
		case UNW_X86_64_R13:
			return "r13";
		case UNW_X86_64_R14:
			return "r14";
		case UNW_X86_64_R15:
			return "r15";
		default:
			return "unknown register";
	}
}

double Registers_x86_64::getFloatRegister(int num) const
{
	ABORT("no x86_64 float registers");
}

void Registers_x86_64::setFloatRegister(int num, double value)
{
	ABORT("no x86_64 float registers");
}

inline v128 Registers_x86_64::getVectorRegister(int num) const
{
	ABORT("no x86_64 vector registers");
}

inline void Registers_x86_64::setVectorRegister(int num, v128 value)
{
	ABORT("no x86_64 vector registers");
}


///
/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC process.  
///
class Registers_ppc
{
public:	
					Registers_ppc();
					Registers_ppc(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);
	void			jumpto();
	const char*		getRegisterName(int num);
	uint64_t		getSP() const			{ return fRegisters.__r1; }
	void			setSP(uint64_t value)	{ fRegisters.__r1 = value; }
	uint64_t		getIP() const			{ return fRegisters.__srr0; }
	void			setIP(uint64_t value)	{ fRegisters.__srr0 = value; }
private:
	struct ppc_thread_state_t
	{
		unsigned int __srr0;	/* Instruction address register (PC) */
		unsigned int __srr1;	/* Machine state register (supervisor) */
		unsigned int __r0;
		unsigned int __r1;
		unsigned int __r2;
		unsigned int __r3;
		unsigned int __r4;
		unsigned int __r5;
		unsigned int __r6;
		unsigned int __r7;
		unsigned int __r8;
		unsigned int __r9;
		unsigned int __r10;
		unsigned int __r11;
		unsigned int __r12;
		unsigned int __r13;
		unsigned int __r14;
		unsigned int __r15;
		unsigned int __r16;
		unsigned int __r17;
		unsigned int __r18;
		unsigned int __r19;
		unsigned int __r20;
		unsigned int __r21;
		unsigned int __r22;
		unsigned int __r23;
		unsigned int __r24;
		unsigned int __r25;
		unsigned int __r26;
		unsigned int __r27;
		unsigned int __r28;
		unsigned int __r29;
		unsigned int __r30;
		unsigned int __r31;
		unsigned int __cr;	/* Condition register */
		unsigned int __xer;	/* User's integer exception register */
		unsigned int __lr;	/* Link register */
		unsigned int __ctr;	/* Count register */
		unsigned int __mq;	/* MQ register (601 only) */
		unsigned int __vrsave;	/* Vector Save Register */
	};
	
	struct ppc_float_state_t
	{
		double  __fpregs[32];

		unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
		unsigned int __fpscr;	/* floating point status register */
	};

	ppc_thread_state_t	fRegisters;
	ppc_float_state_t	fFloatRegisters;
	v128				fVectorRegisters[32];	// offset 424 
};



inline Registers_ppc::Registers_ppc(const void* registers) 
{
	COMPILE_TIME_ASSERT( sizeof(Registers_ppc) < sizeof(unw_context_t) );
	fRegisters = *((ppc_thread_state_t*)registers); 
	fFloatRegisters = *((ppc_float_state_t*)((char*)registers+160));
	memcpy(fVectorRegisters, ((char*)registers+424), sizeof(fVectorRegisters));
}

inline Registers_ppc::Registers_ppc() 
{ 
	bzero(&fRegisters, sizeof(fRegisters)); 
	bzero(&fFloatRegisters, sizeof(fFloatRegisters)); 
	bzero(&fVectorRegisters, sizeof(fVectorRegisters)); 
}


inline bool Registers_ppc::validRegister(int regNum) const
{
	if ( regNum == UNW_REG_IP )
		return true;
	if ( regNum == UNW_REG_SP )
		return true;
	if ( regNum == UNW_PPC_VRSAVE )
		return true;
	if ( regNum < 0 )
		return false;
	if ( regNum <= UNW_PPC_R31 )
		return true;
	if ( regNum == UNW_PPC_MQ )
		return true;
	if ( regNum == UNW_PPC_LR )
		return true;
	if ( regNum == UNW_PPC_CTR )
		return true;
	if ( (UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7) )
		return true;
	return false;
}


inline uint32_t Registers_ppc::getRegister(int regNum) const
{
	switch ( regNum ) {
		case UNW_REG_IP:
			return fRegisters.__srr0;
		case UNW_REG_SP:
			return fRegisters.__r1;
		case UNW_PPC_R0:
			return fRegisters.__r0;
		case UNW_PPC_R1:
			return fRegisters.__r1;
		case UNW_PPC_R2:
			return fRegisters.__r2;
		case UNW_PPC_R3:
			return fRegisters.__r3;
		case UNW_PPC_R4:
			return fRegisters.__r4;
		case UNW_PPC_R5:
			return fRegisters.__r5;
		case UNW_PPC_R6:
			return fRegisters.__r6;
		case UNW_PPC_R7:
			return fRegisters.__r7;
		case UNW_PPC_R8:
			return fRegisters.__r8;
		case UNW_PPC_R9:
			return fRegisters.__r9;
		case UNW_PPC_R10:
			return fRegisters.__r10;
		case UNW_PPC_R11:
			return fRegisters.__r11;
		case UNW_PPC_R12:
			return fRegisters.__r12;
		case UNW_PPC_R13:
			return fRegisters.__r13;
		case UNW_PPC_R14:
			return fRegisters.__r14;
		case UNW_PPC_R15:
			return fRegisters.__r15;
		case UNW_PPC_R16:
			return fRegisters.__r16;
		case UNW_PPC_R17:
			return fRegisters.__r17;
		case UNW_PPC_R18:
			return fRegisters.__r18;
		case UNW_PPC_R19:
			return fRegisters.__r19;
		case UNW_PPC_R20:
			return fRegisters.__r20;
		case UNW_PPC_R21:
			return fRegisters.__r21;
		case UNW_PPC_R22:
			return fRegisters.__r22;
		case UNW_PPC_R23:
			return fRegisters.__r23;
		case UNW_PPC_R24:
			return fRegisters.__r24;
		case UNW_PPC_R25:
			return fRegisters.__r25;
		case UNW_PPC_R26:
			return fRegisters.__r26;
		case UNW_PPC_R27:
			return fRegisters.__r27;
		case UNW_PPC_R28:
			return fRegisters.__r28;
		case UNW_PPC_R29:
			return fRegisters.__r29;
		case UNW_PPC_R30:
			return fRegisters.__r30;
		case UNW_PPC_R31:
			return fRegisters.__r31;
		case UNW_PPC_LR:
			return fRegisters.__lr;
		case UNW_PPC_CR0:
			return (fRegisters.__cr & 0xF0000000);
		case UNW_PPC_CR1:
			return (fRegisters.__cr & 0x0F000000);
		case UNW_PPC_CR2:
			return (fRegisters.__cr & 0x00F00000);
		case UNW_PPC_CR3:
			return (fRegisters.__cr & 0x000F0000);
		case UNW_PPC_CR4:
			return (fRegisters.__cr & 0x0000F000);
		case UNW_PPC_CR5:
			return (fRegisters.__cr & 0x00000F00);
		case UNW_PPC_CR6:
			return (fRegisters.__cr & 0x000000F0);
		case UNW_PPC_CR7:
			return (fRegisters.__cr & 0x0000000F);
		case UNW_PPC_VRSAVE:
			return fRegisters.__vrsave;
	}
	ABORT("unsupported ppc register");
}


inline void Registers_ppc::setRegister(int regNum, uint32_t value)
{
	//fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);	
	switch ( regNum ) {
		case UNW_REG_IP:
			fRegisters.__srr0 = value;
			return;
		case UNW_REG_SP:
			fRegisters.__r1 = value;
			return;
		case UNW_PPC_R0:
			fRegisters.__r0 = value;
			return;
		case UNW_PPC_R1:
			fRegisters.__r1 = value;
			return;
		case UNW_PPC_R2:
			fRegisters.__r2 = value;
			return;
		case UNW_PPC_R3:
			fRegisters.__r3 = value;
			return;
		case UNW_PPC_R4:
			fRegisters.__r4 = value;
			return;
		case UNW_PPC_R5:
			fRegisters.__r5 = value;
			return;
		case UNW_PPC_R6:
			fRegisters.__r6 = value;
			return;
		case UNW_PPC_R7:
			fRegisters.__r7 = value;
			return;
		case UNW_PPC_R8:
			fRegisters.__r8 = value;
			return;
		case UNW_PPC_R9:
			fRegisters.__r9 = value;
			return;
		case UNW_PPC_R10:
			fRegisters.__r10 = value;
			return;
		case UNW_PPC_R11:
			fRegisters.__r11 = value;
			return;
		case UNW_PPC_R12:
			fRegisters.__r12 = value;
			return;
		case UNW_PPC_R13:
			fRegisters.__r13 = value;
			return;
		case UNW_PPC_R14:
			fRegisters.__r14 = value;
			return;
		case UNW_PPC_R15:
			fRegisters.__r15 = value;
			return;
		case UNW_PPC_R16:
			fRegisters.__r16 = value;
			return;
		case UNW_PPC_R17:
			fRegisters.__r17 = value;
			return;
		case UNW_PPC_R18:
			fRegisters.__r18 = value;
			return;
		case UNW_PPC_R19:
			fRegisters.__r19 = value;
			return;
		case UNW_PPC_R20:
			fRegisters.__r20 = value;
			return;
		case UNW_PPC_R21:
			fRegisters.__r21 = value;
			return;
		case UNW_PPC_R22:
			fRegisters.__r22 = value;
			return;
		case UNW_PPC_R23:
			fRegisters.__r23 = value;
			return;
		case UNW_PPC_R24:
			fRegisters.__r24 = value;
			return;
		case UNW_PPC_R25:
			fRegisters.__r25 = value;
			return;
		case UNW_PPC_R26:
			fRegisters.__r26 = value;
			return;
		case UNW_PPC_R27:
			fRegisters.__r27 = value;
			return;
		case UNW_PPC_R28:
			fRegisters.__r28 = value;
			return;
		case UNW_PPC_R29:
			fRegisters.__r29 = value;
			return;
		case UNW_PPC_R30:
			fRegisters.__r30 = value;
			return;
		case UNW_PPC_R31:
			fRegisters.__r31 = value;
			return;
		case UNW_PPC_MQ:
			fRegisters.__mq = value;
			return;
		case UNW_PPC_LR:
			fRegisters.__lr = value;
			return;
		case UNW_PPC_CTR:
			fRegisters.__ctr = value;
			return;
		case UNW_PPC_CR0:
			fRegisters.__cr &= 0x0FFFFFFF;
			fRegisters.__cr |= (value & 0xF0000000);
			return;
		case UNW_PPC_CR1:
			fRegisters.__cr &= 0xF0FFFFFF;
			fRegisters.__cr |= (value & 0x0F000000);
			return;
		case UNW_PPC_CR2:
			fRegisters.__cr &= 0xFF0FFFFF;
			fRegisters.__cr |= (value & 0x00F00000);
			return;
		case UNW_PPC_CR3:
			fRegisters.__cr &= 0xFFF0FFFF;
			fRegisters.__cr |= (value & 0x000F0000);
			return;
		case UNW_PPC_CR4:
			fRegisters.__cr &= 0xFFFF0FFF;
			fRegisters.__cr |= (value & 0x0000F000);
			return;
		case UNW_PPC_CR5:
			fRegisters.__cr &= 0xFFFFF0FF;
			fRegisters.__cr |= (value & 0x00000F00);
			return;
		case UNW_PPC_CR6:
			fRegisters.__cr &= 0xFFFFFF0F;
			fRegisters.__cr |= (value & 0x000000F0);
			return;
		case UNW_PPC_CR7:
			fRegisters.__cr &= 0xFFFFFFF0;
			fRegisters.__cr |= (value & 0x0000000F);
			return;
		case UNW_PPC_VRSAVE:
			fRegisters.__vrsave = value;
			return;
			// not saved
			return;
		case UNW_PPC_XER:
			fRegisters.__xer = value;
			return;
		case UNW_PPC_AP:
		case UNW_PPC_VSCR:
		case UNW_PPC_SPEFSCR:
			// not saved
			return;
	}
	ABORT("unsupported ppc register");
}

inline bool Registers_ppc::validFloatRegister(int regNum) const
{
	if ( regNum < UNW_PPC_F0 )
		return false;
	if ( regNum > UNW_PPC_F31 )
		return false;
	return true;
}

inline double Registers_ppc::getFloatRegister(int regNum) const
{
	assert(validFloatRegister(regNum));
	return fFloatRegisters.__fpregs[regNum-UNW_PPC_F0];
}

inline void Registers_ppc::setFloatRegister(int regNum, double value)
{
	//fprintf(stderr, "Registers_ppc::setFloatRegister(%d, %g))\n", regNum, value);
	assert(validFloatRegister(regNum));
	fFloatRegisters.__fpregs[regNum-UNW_PPC_F0] = value;
}


inline bool Registers_ppc::validVectorRegister(int regNum) const
{
	if ( regNum < UNW_PPC_V0 )
		return false;
	if ( regNum > UNW_PPC_V31 )
		return false;
	return true;
}

v128 Registers_ppc::getVectorRegister(int regNum) const
{
	assert(validVectorRegister(regNum));
	v128 result = fVectorRegisters[regNum-UNW_PPC_V0];
	//fprintf(stderr, "Registers_ppc::getVectorRegister(this=%p, %d) => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n", 
	//		this, regNum, result.vec[0], result.vec[1], result.vec[2], result.vec[3]);
	return result;
}

void Registers_ppc::setVectorRegister(int regNum, v128 value) 
{
	assert(validVectorRegister(regNum));
	//fprintf(stderr, "Registers_ppc::setVectorRegister(this=%p, %d) <0x%08X, 0x%08X, 0x%08X, 0x%08X> => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n", 
	//		this, regNum, fVectorRegisters[regNum-UNW_PPC_V0].vec[0], fVectorRegisters[regNum-UNW_PPC_V0].vec[1], fVectorRegisters[regNum-UNW_PPC_V0].vec[2], 
	//			fVectorRegisters[regNum-UNW_PPC_V0].vec[3], value.vec[0], value.vec[1], value.vec[2], value.vec[3]);
	fVectorRegisters[regNum-UNW_PPC_V0] = value;
}


inline const char* Registers_ppc::getRegisterName(int regNum)
{
	switch ( regNum ) {
		case UNW_REG_IP:
			return "ip";
		case UNW_REG_SP:
			return "sp";
		case UNW_PPC_R0:
			return "r0";
		case UNW_PPC_R1:
			return "r1";
		case UNW_PPC_R2:
			return "r2";
		case UNW_PPC_R3:
			return "r3";
		case UNW_PPC_R4:
			return "r4";
		case UNW_PPC_R5:
			return "r5";
		case UNW_PPC_R6:
			return "r6";
		case UNW_PPC_R7:
			return "r7";
		case UNW_PPC_R8:
			return "r8";
		case UNW_PPC_R9:
			return "r9";
		case UNW_PPC_R10:
			return "r10";
		case UNW_PPC_R11:
			return "r11";
		case UNW_PPC_R12:
			return "r12";
		case UNW_PPC_R13:
			return "r13";
		case UNW_PPC_R14:
			return "r14";
		case UNW_PPC_R15:
			return "r15";
		case UNW_PPC_R16:
			return "r16";
		case UNW_PPC_R17:
			return "r17";
		case UNW_PPC_R18:
			return "r18";
		case UNW_PPC_R19:
			return "r19";
		case UNW_PPC_R20:
			return "r20";
		case UNW_PPC_R21:
			return "r21";
		case UNW_PPC_R22:
			return "r22";
		case UNW_PPC_R23:
			return "r23";
		case UNW_PPC_R24:
			return "r24";
		case UNW_PPC_R25:
			return "r25";
		case UNW_PPC_R26:
			return "r26";
		case UNW_PPC_R27:
			return "r27";
		case UNW_PPC_R28:
			return "r28";
		case UNW_PPC_R29:
			return "r29";
		case UNW_PPC_R30:
			return "r30";
		case UNW_PPC_R31:
			return "r31";
		case UNW_PPC_F0:
			return "fp0";
		case UNW_PPC_F1:
			return "fp1";
		case UNW_PPC_F2:
			return "fp2";
		case UNW_PPC_F3:
			return "fp3";
		case UNW_PPC_F4:
			return "fp4";
		case UNW_PPC_F5:
			return "fp5";
		case UNW_PPC_F6:
			return "fp6";
		case UNW_PPC_F7:
			return "fp7";
		case UNW_PPC_F8:
			return "fp8";
		case UNW_PPC_F9:
			return "fp9";
		case UNW_PPC_F10:
			return "fp10";
		case UNW_PPC_F11:
			return "fp11";
		case UNW_PPC_F12:
			return "fp12";
		case UNW_PPC_F13:
			return "fp13";
		case UNW_PPC_F14:
			return "fp14";
		case UNW_PPC_F15:
			return "fp15";
		case UNW_PPC_F16:
			return "fp16";
		case UNW_PPC_F17:
			return "fp17";
		case UNW_PPC_F18:
			return "fp18";
		case UNW_PPC_F19:
			return "fp19";
		case UNW_PPC_F20:
			return "fp20";
		case UNW_PPC_F21:
			return "fp21";
		case UNW_PPC_F22:
			return "fp22";
		case UNW_PPC_F23:
			return "fp23";
		case UNW_PPC_F24:
			return "fp24";
		case UNW_PPC_F25:
			return "fp25";
		case UNW_PPC_F26:
			return "fp26";
		case UNW_PPC_F27:
			return "fp27";
		case UNW_PPC_F28:
			return "fp28";
		case UNW_PPC_F29:
			return "fp29";
		case UNW_PPC_F30:
			return "fp30";
		case UNW_PPC_F31:
			return "fp31";
		case UNW_PPC_LR:
			return "lr";
		default:
			return "unknown register";
	}

}





struct arm_thread_state64_t
{
	__uint64_t    __x[29];	/* General purpose registers x0-x28 */
	__uint64_t    __fp;		/* Frame pointer x29 */
	__uint64_t    __lr;		/* Link register x30 */
	__uint64_t    __sp;		/* Stack pointer x31 */
	__uint64_t    __pc;		/* Program counter */
	__uint32_t    __cpsr;	/* Current program status register */
	__uint32_t	  padding[3]; /* round up struct size to be 0x110 */
};


///
/// Registers_arm64  holds the register state of a thread in a 64-bit intel process.  
///
class Registers_arm64
{
public:	
					Registers_arm64();
					Registers_arm64(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();
	uint64_t		getSP()	const			{ return fRegisters.__sp; }
	void			setSP(uint64_t value)	{ fRegisters.__sp = value; }
	uint64_t		getIP()	const			{ return fRegisters.__pc; }
	void			setIP(uint64_t value)	{ fRegisters.__pc = value; }
	uint64_t		getFP() const			{ return fRegisters.__fp; }
	void			setFP(uint64_t value)	{ fRegisters.__fp = value; }
private:
	arm_thread_state64_t	fRegisters;
	double					fHalfVectorRegisters[32];
	// Currently only the lower double in 128-bit vectore registers
	// is perserved during unwinding.  We could define new register
	// numbers (> 96) which mean whole vector registers, then this
	// struct would need to change to contain whole vector registers.
};

inline Registers_arm64::Registers_arm64(const void* registers)
{
	COMPILE_TIME_ASSERT( sizeof(Registers_arm64) < sizeof(unw_context_t) );
	fRegisters = *((arm_thread_state64_t*)registers); 
}

inline Registers_arm64::Registers_arm64()
{
	bzero(&fRegisters, sizeof(fRegisters)); 
	bzero(&fRegisters, sizeof(fHalfVectorRegisters)); 
}


inline bool Registers_arm64::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 > 95 )
		return false;
	if ( (regNum > 31) && (regNum < 64) )
		return false;
	return true;
}

inline uint64_t Registers_arm64::getRegister(int regNum) const
{
	if ( regNum == UNW_REG_IP )
		return fRegisters.__pc;
	if ( regNum == UNW_REG_SP )
		return fRegisters.__sp;
	if ( (regNum >= 0) && (regNum < 32) )
		return fRegisters.__x[regNum];
	ABORT("unsupported arm64 register");
}

inline void Registers_arm64::setRegister(int regNum, uint64_t value)
{
	if ( regNum == UNW_REG_IP )
		fRegisters.__pc = value;
	else if ( regNum == UNW_REG_SP )
		fRegisters.__sp = value;
	else if ( (regNum >= 0) && (regNum < 32) )
		fRegisters.__x[regNum] = value;
	else
		ABORT("unsupported arm64 register");
}

inline const char* Registers_arm64::getRegisterName(int regNum)
{
	switch (regNum) {
		case UNW_REG_IP:
			return "pc";
		case UNW_REG_SP:
			return "sp";
		case UNW_ARM64_X0:
			return "x0";
		case UNW_ARM64_X1:
			return "x1";
		case UNW_ARM64_X2:
			return "x2";
		case UNW_ARM64_X3:
			return "x3";
		case UNW_ARM64_X4:
			return "x4";
		case UNW_ARM64_X5:
			return "x5";
		case UNW_ARM64_X6:
			return "x6";
		case UNW_ARM64_X7:
			return "x7";
		case UNW_ARM64_X8:
			return "x8";
		case UNW_ARM64_X9:
			return "x9";
		case UNW_ARM64_X10:
			return "x10";
		case UNW_ARM64_X11:
			return "x11";
		case UNW_ARM64_X12:
			return "x12";
		case UNW_ARM64_X13:
			return "x13";
		case UNW_ARM64_X14:
			return "x14";
		case UNW_ARM64_X15:
			return "x15";
		case UNW_ARM64_X16:
			return "x16";
		case UNW_ARM64_X17:
			return "x17";
		case UNW_ARM64_X18:
			return "x18";
		case UNW_ARM64_X19:
			return "x19";
		case UNW_ARM64_X20:
			return "x20";
		case UNW_ARM64_X21:
			return "x21";
		case UNW_ARM64_X22:
			return "x22";
		case UNW_ARM64_X23:
			return "x23";
		case UNW_ARM64_X24:
			return "x24";
		case UNW_ARM64_X25:
			return "x25";
		case UNW_ARM64_X26:
			return "x26";
		case UNW_ARM64_X27:
			return "x27";
		case UNW_ARM64_X28:
			return "x28";
		case UNW_ARM64_X29:
			return "fp";
		case UNW_ARM64_X30:
			return "lr";
		case UNW_ARM64_X31:
			return "sp";
		case UNW_ARM64_D0:
			return "d0";
		case UNW_ARM64_D1:
			return "d1";
		case UNW_ARM64_D2:
			return "d2";
		case UNW_ARM64_D3:
			return "d3";
		case UNW_ARM64_D4:
			return "d4";
		case UNW_ARM64_D5:
			return "d5";
		case UNW_ARM64_D6:
			return "d6";
		case UNW_ARM64_D7:
			return "d7";
		case UNW_ARM64_D8:
			return "d8";
		case UNW_ARM64_D9:
			return "d9";
		case UNW_ARM64_D10:
			return "d10";
		case UNW_ARM64_D11:
			return "d11";
		case UNW_ARM64_D12:
			return "d12";
		case UNW_ARM64_D13:
			return "d13";
		case UNW_ARM64_D14:
			return "d14";
		case UNW_ARM64_D15:
			return "d15";
		case UNW_ARM64_D16:
			return "d16";
		case UNW_ARM64_D17:
			return "d17";
		case UNW_ARM64_D18:
			return "d18";
		case UNW_ARM64_D19:
			return "d19";
		case UNW_ARM64_D20:
			return "d20";
		case UNW_ARM64_D21:
			return "d21";
		case UNW_ARM64_D22:
			return "d22";
		case UNW_ARM64_D23:
			return "d23";
		case UNW_ARM64_D24:
			return "d24";
		case UNW_ARM64_D25:
			return "d25";
		case UNW_ARM64_D26:
			return "d26";
		case UNW_ARM64_D27:
			return "d27";
		case UNW_ARM64_D28:
			return "d28";
		case UNW_ARM64_D29:
			return "d29";
		case UNW_ARM64_D30:
			return "d30";
		case UNW_ARM64_D31:
			return "d31";
		default:
			return "unknown register";
	}
}

bool Registers_arm64::validFloatRegister(int regNum) const
{
	if ( regNum < UNW_ARM64_D0 )
		return false;
	if ( regNum > UNW_ARM64_D31 )
		return false;
	return true;
}


double Registers_arm64::getFloatRegister(int regNum) const
{
	assert(validFloatRegister(regNum));
	return fHalfVectorRegisters[regNum-UNW_ARM64_D0];
}

void Registers_arm64::setFloatRegister(int regNum, double value)
{
	assert(validFloatRegister(regNum));
	fHalfVectorRegisters[regNum-UNW_ARM64_D0] = value;
}

inline bool Registers_arm64::validVectorRegister(int regNum) const
{
	return false;
}

inline v128 Registers_arm64::getVectorRegister(int regNum) const
{
	ABORT("no arm64 vector register support yet");
}

inline void Registers_arm64::setVectorRegister(int regNum, v128 value)
{
	ABORT("no arm64 vector register support yet");
}



} // namespace libunwind 



#endif // __REGISTERS_HPP__




