/*
Copyright (C) 2006 - 2009 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 <QString>
#include <QtAlgorithms>
#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, backup.st + 8, st);
	qCopy(backup.dr, backup.dr + 8, dr);
}

//------------------------------------------------------------------------------
// 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, st + 8, backup.st);
	qCopy(dr, dr + 8, backup.dr);
}

//------------------------------------------------------------------------------
// 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::address_t State::flags() const {
	return rflags;
}

//------------------------------------------------------------------------------
// Name: value(const QString &reg)
// Desc: a function to return the value of a register based on it's name
//------------------------------------------------------------------------------
Register State::value(const QString &reg) const {

	const QString lreg = reg.toLower();

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

	return Register();
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
Register State::operator[](const QString &reg) const {
	return value(reg);
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void State::setRegister(const QString &name, edb::reg_t value) {
	const QString lreg = name.toLower();

	if(lreg == "rax") { rax = value; }
	else if(lreg == "rbx") { rbx = value; }
	else if(lreg == "rcx") { rcx = value; }
	else if(lreg == "rdx") { rdx = value; }
	else if(lreg == "rbp") { rbp = value; }
	else if(lreg == "rsp") { rsp = value; }
	else if(lreg == "rsi") { rsi = value; }
	else if(lreg == "rdi") { rdi = value; }
	else if(lreg == "r8") { r8 = value; }
	else if(lreg == "r9") { r9 = value; }
	else if(lreg == "r10") { r10 = value; }
	else if(lreg == "r11") { r11 = value; }
	else if(lreg == "r12") { r12 = value; }
	else if(lreg == "r13") { r13 = value; }
	else if(lreg == "r14") { r14 = value; }
	else if(lreg == "r15") { r15 = value; }
	else if(lreg == "rip") { rip = value; }
	else if(lreg == "cs") { cs = value; }
	else if(lreg == "ds") { ds = value; }
	else if(lreg == "es") { es = value; }
	else if(lreg == "fs") { fs = value; }
	else if(lreg == "gs") { gs = value; }
	else if(lreg == "ss") { ss = value; }
	else if(lreg == "rflags") { rflags = value; }
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void State::adjustStack(int bytes) {
	rsp += bytes;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
void State::setInstructionPointer(edb::address_t value) {
	rip = value;
}
