/*
Copyright (C) 2006 Evan Teran
                   eteran@alum.rit.edu

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef STATE_20060715_H_
#define STATE_20060715_H_

#include "Types.h"

class QString;

class State {
public:
	State();

private:
	// not copyable, use to/fromBackup routines
	State(const State &other);
	State &operator=(const State &other);
	
public:
	// what an FPU register looks like	
	struct i387Register {
	public:
		i387Register();
		i387Register(const i387Register &other);
		i387Register &operator=(const i387Register &other);
	public:
		double toDouble() const;
	public:
		bool operator==(const i387Register &other) const;
		bool operator!=(const i387Register &other) const;
	public:
		union {
			quint8 raw[sizeof(long double)];
			long double raw_ldouble;
		};
	};

public:
	// the actual state storage
	edb::reg_t rbx;
	edb::reg_t rcx;
	edb::reg_t rdx;
	edb::reg_t rsi;
	edb::reg_t rdi;
	edb::reg_t rbp;
	edb::reg_t rax;
	edb::reg_t rsp;
	edb::reg_t r8;
	edb::reg_t r9;
	edb::reg_t r10;	
	edb::reg_t r11;
	edb::reg_t r12;	
	edb::reg_t r13;
	edb::reg_t r14;
	edb::reg_t r15;
	edb::reg_t cs;
	edb::reg_t ds;
	edb::reg_t es;
	edb::reg_t fs;
	edb::reg_t gs;
	edb::reg_t ss;
	edb::reg_t rip;
	edb::reg_t rflags;
	edb::reg_t fs_base;
	edb::reg_t gs_base;
	edb::reg_t orig_rax;
	
	i387Register st[8];
	edb::reg_t dr[8];
	
public:
	void adjustStack(int bytes);
	void setInstructionPointer(edb::address_t value);
	edb::address_t instructionPointer() const;
	edb::address_t stackPointer() const;
	edb::address_t framePointer() const;
	void frombackup(const State &backup);
	void toBackup(State &backup) const;
	edb::reg_t value(const QString &reg, bool &ok) const;
	edb::reg_t value(const QString &reg) const;
	void clear();
	
public:
	enum {		
		// groups, these catagories should remain as portable as possible
		REG_GPR		= 0x0001,
		REG_IP		= 0x0002,
		REG_SEG		= 0x0004,
		REG_COND	= 0x0008,
		REG_FPU		= 0x0010,
		REG_ANY		= -1
	};
};

#endif
