/*
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.
*/

#include "State.h"
#include "Util.h"
#include "DebuggerCoreInterface.h"
#include <QString>
#include <cstring>

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
State::i387Register::i387Register() {
	std::memset(raw, 0, sizeof(raw));
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
State::i387Register::i387Register(const i387Register &other) {
	std::memcpy(raw, other.raw, sizeof(raw));
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
State::i387Register &State::i387Register::operator=(const State::i387Register &other) {
	if(this != &other) {
		std::memcpy(raw, other.raw, sizeof(raw));
	}
	
	return *this;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
double State::i387Register::toDouble() const {
	return static_cast<double>(raw_ldouble);
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
bool State::i387Register::operator==(const State::i387Register &other) const {
	return std::memcmp(raw, other.raw, sizeof(raw)) == 0;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
bool State::i387Register::operator!=(const State::i387Register &other) const {
	return !(*this == other);
}

//------------------------------------------------------------------------------
// Name: State()
// Desc: constructor
//------------------------------------------------------------------------------
State::State() {
	clear();
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void State::frombackup(const State &backup) {
	rbx = backup.rbx;
	rcx = backup.rcx;
	rdx = backup.rdx;
	rsi = backup.rsi;
	rdi = backup.rdi;
	rbp = backup.rbp;
	rax = backup.rax;
	rsp = backup.rsp;
	r8 = backup.r8;
	r9 = backup.r9;
	r10 = backup.r10;
	r11 = backup.r11;
	r12 = backup.r12;
	r13 = backup.r13;
	r14 = backup.r14;
	r15 = backup.r15;
	cs = backup.cs;
	ds = backup.ds;
	es = backup.es;
	fs = backup.fs;
	gs = backup.gs;
	ss = backup.ss;
	rip = backup.rip;
	rflags = backup.rflags;
	orig_rax = backup.orig_rax;
	fs_base = backup.fs_base;
	gs_base = backup.gs_base;
	
	qCopy(&backup.st[0], &backup.st[8], &st[0]);
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void State::toBackup(State &backup) const {
	backup.rbx = rbx;
	backup.rcx = rcx;
	backup.rdx = rdx;
	backup.rsi = rsi;
	backup.rdi = rdi;
	backup.rbp = rbp;
	backup.rax = rax;
	backup.rsp = rsp;
	backup.r8 = r8;
	backup.r9 = r9;
	backup.r10 = r10;
	backup.r11 = r11;
	backup.r12 = r12;
	backup.r13 = r13;
	backup.r14 = r14;
	backup.r15 = r15;
	backup.cs = cs;
	backup.ds = ds;
	backup.es = es;
	backup.fs = fs;
	backup.gs = gs;
	backup.ss = ss;
	backup.rip = rip;
	backup.rflags = rflags;
	backup.orig_rax = orig_rax;
	backup.fs_base = fs_base;
	backup.gs_base = gs_base;
	
	qCopy(&st[0], &st[8], &backup.st[0]);
}

//------------------------------------------------------------------------------
// Name: clear()
// Desc: 
//------------------------------------------------------------------------------
void State::clear() {
	rbx = 0;
	rcx = 0;
	rdx = 0;
	rsi = 0;
	rdi = 0;
	rbp = 0;
	rax = 0;
	rsp = 0;
	r8 = 0;
	r9 = 0;
	r10 = 0;
	r11 = 0;
	r12 = 0;
	r13 = 0;
	r14 = 0;
	r15 = 0;
	cs = 0;
	ds = 0;
	es = 0;
	fs = 0;
	gs = 0;
	ss = 0;
	rip = 0;
	rflags = 0;
	orig_rax = 0;
	fs_base = 0;
	gs_base = 0;
	
	std::memset(st, 0, sizeof(st));
	std::memset(dr, 0, sizeof(dr));
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
edb::address_t State::instructionPointer() const {
	return rip;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
edb::address_t State::stackPointer() const {
	return rsp;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
edb::address_t State::framePointer() const {
	return rbp;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
edb::reg_t State::value(const QString &reg) const {
	bool ok;
	return value(reg, ok);
}

//------------------------------------------------------------------------------
// Name: value(const QString &reg, bool *ok)
// Desc: a function to return the value of a register based on it's name
//------------------------------------------------------------------------------
edb::reg_t State::value(const QString &reg, bool &ok) const {
	edb::reg_t ret = 0;
	ok = false;

	const QString lreg = reg.toLower();

	if(lreg == "rax") { ret = rax; ok = true; }
	else if(lreg == "rbx") { ret = rbx; ok = true; }
	else if(lreg == "rcx") { ret = rcx; ok = true; }
	else if(lreg == "rdx") { ret = rdx; ok = true; }
	else if(lreg == "rbp") { ret = rbp; ok = true; }
	else if(lreg == "rsp") { ret = rsp; ok = true; }
	else if(lreg == "rsi") { ret = rsi; ok = true; }
	else if(lreg == "rdi") { ret = rdi; ok = true; }
	else if(lreg == "rip") { ret = rip; ok = true; }
	else if(lreg == "r8") { ret = r8; ok = true; }
	else if(lreg == "r9") { ret = r9; ok = true; }
	else if(lreg == "r10") { ret = r10; ok = true; }
	else if(lreg == "r11") { ret = r11; ok = true; }
	else if(lreg == "r12") { ret = r12; ok = true; }
	else if(lreg == "r13") { ret = r13; ok = true; }
	else if(lreg == "r14") { ret = r14; ok = true; }
	else if(lreg == "r15") { ret = r15; ok = true; }
	else if(lreg == "eax") { ret = rax & 0xffffffff; ok = true; }
	else if(lreg == "ebx") { ret = rbx & 0xffffffff; ok = true; }
	else if(lreg == "ecx") { ret = rcx & 0xffffffff; ok = true; }
	else if(lreg == "edx") { ret = rdx & 0xffffffff; ok = true; }
	else if(lreg == "ebp") { ret = rbp & 0xffffffff; ok = true; }
	else if(lreg == "esp") { ret = rsp & 0xffffffff; ok = true; }
	else if(lreg == "esi") { ret = rsi & 0xffffffff; ok = true; }
	else if(lreg == "edi") { ret = rdi & 0xffffffff; ok = true; }
	else if(lreg == "r8d") { ret = r8 & 0xffffffff; ok = true; }
	else if(lreg == "r9d") { ret = r9 & 0xffffffff; ok = true; }
	else if(lreg == "r10d") { ret = r10 & 0xffffffff; ok = true; }
	else if(lreg == "r11d") { ret = r11 & 0xffffffff; ok = true; }
	else if(lreg == "r12d") { ret = r12 & 0xffffffff; ok = true; }
	else if(lreg == "r13d") { ret = r13 & 0xffffffff; ok = true; }
	else if(lreg == "r14d") { ret = r14 & 0xffffffff; ok = true; }
	else if(lreg == "r15d") { ret = r15 & 0xffffffff; ok = true; }
	else if(lreg == "ax") { ret = rax & 0xffff; ok = true; }
	else if(lreg == "bx") { ret = rbx & 0xffff; ok = true; }
	else if(lreg == "cx") { ret = rcx & 0xffff; ok = true; }
	else if(lreg == "dx") { ret = rdx & 0xffff; ok = true; }
	else if(lreg == "bp") { ret = rbp & 0xffff; ok = true; }
	else if(lreg == "sp") { ret = rsp & 0xffff; ok = true; }
	else if(lreg == "si") { ret = rsi & 0xffff; ok = true; }
	else if(lreg == "di") { ret = rdi & 0xffff; ok = true; }
	else if(lreg == "r8w") { ret = r8 & 0xffff; ok = true; }
	else if(lreg == "r9w") { ret = r9 & 0xffff; ok = true; }
	else if(lreg == "r10w") { ret = r10 & 0xffff; ok = true; }
	else if(lreg == "r11w") { ret = r11 & 0xffff; ok = true; }
	else if(lreg == "r12w") { ret = r12 & 0xffff; ok = true; }
	else if(lreg == "r13w") { ret = r13 & 0xffff; ok = true; }
	else if(lreg == "r14w") { ret = r14 & 0xffff; ok = true; }
	else if(lreg == "r15w") { ret = r15 & 0xffff; ok = true; }
	else if(lreg == "al") { ret = rax & 0xff; ok = true; }
	else if(lreg == "bl") { ret = rbx & 0xff; ok = true; }
	else if(lreg == "cl") { ret = rcx & 0xff; ok = true; }
	else if(lreg == "dl") { ret = rdx & 0xff; ok = true; }
	else if(lreg == "ah") { ret = (rax >> 8) & 0xff; ok = true; }
	else if(lreg == "bh") { ret = (rbx >> 8) & 0xff; ok = true; }
	else if(lreg == "ch") { ret = (rcx >> 8) & 0xff; ok = true; }
	else if(lreg == "dh") { ret = (rdx >> 8) & 0xff; ok = true; }
	else if(lreg == "r8b") { ret = r8 & 0xff; ok = true; }
	else if(lreg == "r9b") { ret = r9 & 0xff; ok = true; }
	else if(lreg == "r10b") { ret = r10 & 0xff; ok = true; }
	else if(lreg == "r11b") { ret = r11 & 0xff; ok = true; }
	else if(lreg == "r12b") { ret = r12 & 0xff; ok = true; }
	else if(lreg == "r13b") { ret = r13 & 0xff; ok = true; }
	else if(lreg == "r14b") { ret = r14 & 0xff; ok = true; }
	else if(lreg == "r15b") { ret = r15 & 0xff; ok = true; }
	else if(lreg == "cs") { ret = 0; ok = true; }
	else if(lreg == "ds") { ret = 0; ok = true; }
	else if(lreg == "es") { ret = 0; ok = true; }
	else if(lreg == "fs") { ret = fs_base; ok = true; }
	else if(lreg == "gs") { ret = gs_base; ok = true; }
	else if(lreg == "ss") { ret = 0; ok = true; }

	return ret;
}

void State::adjustStack(int bytes) {
	rsp += bytes;
}


void State::setInstructionPointer(edb::address_t value) {
	rip = value;
}
