/*
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 "MemoryRegions.h"
#include "SymbolManager.h"
#include "DebuggerCoreInterface.h"
#include "Debugger.h"
#include "Util.h"
#include "State.h"
#include <sstream>
#include <iostream>
#include <string>
#include <QApplication>
#include <QFile>
#include <QTextStream>
#include <QMessageBox>

const unsigned int MemoryRegions::Region::READ	= 1;
const unsigned int MemoryRegions::Region::WRITE	= 1;
const unsigned int MemoryRegions::Region::EXEC	= 1;

//------------------------------------------------------------------------------
// Name: MemoryRegions(edb::pid_t pid)
// Desc: constructor
//------------------------------------------------------------------------------
MemoryRegions::MemoryRegions() : QAbstractItemModel(0), m_PID(0) {
}

//------------------------------------------------------------------------------
// Name: ~MemoryRegions()
// Desc: destructor
//------------------------------------------------------------------------------
MemoryRegions::~MemoryRegions() {
}

//------------------------------------------------------------------------------
// Name: setPID(edb::pid_t pid)
// Desc: 
//------------------------------------------------------------------------------
void MemoryRegions::setPID(edb::pid_t pid) {
	m_PID = pid;
	m_Regions.clear();
	sync();
}

//------------------------------------------------------------------------------
// Name: clear()
// Desc: 
//------------------------------------------------------------------------------
void MemoryRegions::clear() {
	m_PID = 0;
	m_Regions.clear();
}

//------------------------------------------------------------------------------
// Name: proccessMapLine(const QString &line, Region &region)
// Desc: parses the data from a line of a memory map file
//------------------------------------------------------------------------------
bool MemoryRegions::proccessMapLine(const QString &line, Region &region) {

	bool ret = false;
	return ret;
}

//------------------------------------------------------------------------------
// Name: sync()
// Desc: reads a memory map file line by line
//------------------------------------------------------------------------------
void MemoryRegions::sync() {

	m_Regions.clear();

	if(m_PID != 0) {
	}
	reset();
}

//------------------------------------------------------------------------------
// Name: handleEvent(DebugEvent event)
// Desc: 
//------------------------------------------------------------------------------
void MemoryRegions::Region::handleEvent(DebugEvent event) {
	Q_UNUSED(event);	
	m_Lock = 0;
}

//------------------------------------------------------------------------------
// Name: ~Region()
// Desc: 
//------------------------------------------------------------------------------
MemoryRegions::Region::~Region() {	
}


//------------------------------------------------------------------------------
// Name: setPermissions(bool read, bool write, bool execute)
// Desc: attempts to change the permissions of a given region by injecting
//       shellcode into the debugged process, and executing a mprotect syscall
//       we probably need to ensure that the debug event server thread is not
//       waiting for an event at this moment because we need to catch the "hlt"
//       instruction we injected in order to restore the original code
//       we also probably need this code to work perfectly in order to implement
//       memory access breakpoints
//------------------------------------------------------------------------------
void MemoryRegions::Region::setPermissions(bool read, bool write, bool execute, edb::address_t tempAddress) {
}

//------------------------------------------------------------------------------
// Name: setPermissions(bool read, bool write, bool execute)
// Desc: wrapper around normal set permissions
//------------------------------------------------------------------------------
void MemoryRegions::Region::setPermissions(bool read, bool write, bool execute) {
}

//------------------------------------------------------------------------------
// Name: findRegion(edb::address_t address) const
// Desc: 
//------------------------------------------------------------------------------
bool MemoryRegions::findRegion(edb::address_t address) const {
	foreach(Region i, m_Regions) {
		if(address >= i.start && address < i.end) {
			return true;
		}
	}
	return false;
}

//------------------------------------------------------------------------------
// Name: findRegion(edb::address_t address, MemoryRegions::Region &region) const
// Desc: 
//------------------------------------------------------------------------------
bool MemoryRegions::findRegion(edb::address_t address, MemoryRegions::Region &region) const {

	foreach(Region i, m_Regions) {
		if(address >= i.start && address < i.end) {
			region = i;
			return true;
		}
	}
	return false;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
QVariant MemoryRegions::data(const QModelIndex &index, int role) const {

	if(index.isValid() && role == Qt::DisplayRole) {
	
		const MemoryRegions::Region &region = m_Regions[index.row()];
		QString temp;
	
		switch(index.column()) {
		case 0:
			return temp.sprintf(EDB_FMT_PTR, region.start);
		case 1:
			return temp.sprintf(EDB_FMT_PTR, region.end);
		case 2:
			return QString("%1%2%3").arg(region.readable() ? 'r' : '-').arg(region.writable() ? 'w' : '-').arg(region.executable() ? 'x' : '-' );
		case 3:
			return region.name;
		}
	}
	
	return QVariant();
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
QModelIndex MemoryRegions::index(int row, int column, const QModelIndex &parent) const {
	Q_UNUSED(parent);

	if(row >= m_Regions.size()) {
		return QModelIndex();
	}

	if(column >= 4) {
		return QModelIndex();
	}
	
	return createIndex(row, column, const_cast<Region *>(&m_Regions[row]));
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
QModelIndex MemoryRegions::parent(const QModelIndex &index) const {
	Q_UNUSED(index);
	return QModelIndex(); 
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
int MemoryRegions::rowCount(const QModelIndex &parent) const {
	Q_UNUSED(parent);
	return m_Regions.size();
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
int MemoryRegions::columnCount(const QModelIndex &parent) const {
	Q_UNUSED(parent);
	return 4;
}

//------------------------------------------------------------------------------
// Name: 
// Desc: 
//------------------------------------------------------------------------------
QVariant MemoryRegions::headerData(int section, Qt::Orientation orientation, int role) const {
	if(role == Qt::DisplayRole && orientation == Qt::Horizontal) {
		switch(section) {
		case 0:
			return "Start Address";
		case 1:
			return "End Address";
		case 2:
			return "Permissions";
		case 3:
			return "Name";
		}	
	}
	
	return QVariant();
}

