/**
 * @file op_header.cpp
 * various free function acting on a sample file header
 *
 * @remark Copyright 2004 OProfile authors
 * @remark Read the file COPYING
 *
 * @author John Levon
 * @author Philippe Elie
 * @Modifications Daniel Hansel
 */

#include <cstring>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <set>
#include <sstream>
#include <cstring>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "op_config.h"
#include "op_exception.h"
#include "odb.h"
#include "op_cpu_type.h"
#include "op_file.h"
#include "op_header.h"
#include "op_events.h"
#include "string_manip.h"
#include "format_output.h"
#include "xml_utils.h"
#include "cverb.h"

using namespace std;

extern verbose vbfd;

void op_check_header(opd_header const & h1, opd_header const & h2,
		     string const & filename)
{
	if (h1.mtime != h2.mtime) {
		ostringstream os;
		os << "header timestamps are different ("
		   << h1.mtime << ", " << h2.mtime << ") for "
		   << filename << "\n";
		throw op_fatal_error(os.str());
	}

	if (h1.is_kernel != h2.is_kernel) {
		ostringstream os;
		os << "header is_kernel flags are different for "
		   << filename << "\n";
		throw op_fatal_error(os.str());
	}
	
	// Note that in the generated ELF file for anonymous code the vma
	// of the symbol is exaclty the same vma as the code had during sampling.
	
	// Note that we don't check CPU speed since that can vary
	// freely on the same machine
}


namespace {

set<string> warned_files;

}

bool is_jit_sample(string const & filename)
{
	// suffix for JIT sample files (see FIXME in check_mtime() below)
	string suf = ".jo";
	
	string::size_type pos;
	pos = filename.rfind(suf);
	// for JIT sample files do not output the warning to stderr.
	if (pos != string::npos && pos == filename.size() - suf.size())
		return true;
	else
		return false;
}

void check_mtime(string const & file, opd_header const & header)
{
	time_t const newmtime = op_get_mtime(file.c_str());

	if (newmtime == header.mtime)
		return;

	if (warned_files.find(file) != warned_files.end())
		return;

	warned_files.insert(file);

	// Files we couldn't get mtime of have zero mtime
	if (!header.mtime) {
		// FIXME: header.mtime for JIT sample files is 0. The problem could be that
		//        in opd_mangling.c:opd_open_sample_file() the call of fill_header()
		//        think that the JIT sample file is not a binary file.
		if (is_jit_sample(file)) {
			cverb << vbfd << "warning: could not check that the binary file "
			      << file << " has not been modified since "
			      "the profile was taken. Results may be inaccurate.\n";
		} else {
			cerr << "warning: could not check that the binary file "
			     << file << " has not been modified since "
			     "the profile was taken. Results may be inaccurate.\n";
		}
	} else {
		static bool warned_already = false;

		cerr << "warning: the last modified time of the binary file "
		     "does not match that of the sample file for " << file
		     << "\n";

		if (!warned_already) {
			cerr << "Either this is the wrong binary or the binary "
			"has been modified since the sample file was created.\n";
			warned_already = true;
		}
	}
}


opd_header const read_header(string const & sample_filename)
{
	int fd = open(sample_filename.c_str(), O_RDONLY);
	if (fd < 0)
		throw op_fatal_error("Can't open sample file:" +
				     sample_filename);

	opd_header header;
	if (read(fd, &header, sizeof(header)) != sizeof(header)) {
		close(fd);
		throw op_fatal_error("Can't read sample file header:" +
				     sample_filename);
	}

	if (memcmp(header.magic, OPD_MAGIC, sizeof(header.magic))) {
		close(fd);
		throw op_fatal_error("Invalid sample file, "
				     "bad magic number: " +
				     sample_filename);
	}

	close(fd);

	return header;
}


namespace {

string const op_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count)
{
	string str;

	if (cpu_type == CPU_TIMER_INT) {
		str += "Profiling through timer interrupt";
		return str;
	}

	struct op_event * event = op_find_event(cpu_type, type, um);

	if (!event) {
		event = op_find_event_any(cpu_type, type);
		if (!event) { 
			cerr << "Could not locate event " << int(type) << endl;
			str = "Unknown event";
			return str;
		}
	}

	char const * um_desc = 0;

	for (size_t i = 0; i < event->unit->num; ++i) {
		if (event->unit->um[i].value == um)
			um_desc = event->unit->um[i].desc;
	}

	str += string("Counted ") + event->name;
	str += string(" events (") + event->desc + ")";

	if (cpu_type != CPU_RTC) {
		str += " with a unit mask of 0x";

		ostringstream ss;
		ss << hex << setw(2) << setfill('0') << unsigned(um);
		str += ss.str();

		str += " (";
		str += um_desc ? um_desc : "multiple flags";
		str += ")";
	}

	str += " count " + op_lexical_cast<string>(count);
	return str;
}

string const op_xml_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count)
{
	string unit_mask;

	if (cpu_type == CPU_TIMER_INT || cpu_type == CPU_RTC)
		return xml_utils::get_timer_setup((size_t)count);

	struct op_event * event = op_find_event(cpu_type, type, um);
	if (!event) {
		event = op_find_event_any(cpu_type, type);
		if (!event) { 
			cerr << "Could not locate event " << int(type) << endl;
			return "";
		}
	}

	if (cpu_type != CPU_RTC) {
		ostringstream str_out;
		str_out << um;
		unit_mask = str_out.str();
	}

	return xml_utils::get_event_setup(string(event->name),
		(size_t)count, unit_mask);
}

}

string const describe_header(opd_header const & header)
{
	op_cpu cpu = static_cast<op_cpu>(header.cpu_type);

	if (want_xml)
		return op_xml_print_event(cpu, header.ctr_event,
	                      header.ctr_um, header.ctr_count);
	else
		return op_print_event(cpu, header.ctr_event,
	                      header.ctr_um, header.ctr_count);
}


string const describe_cpu(opd_header const & header)
{
	op_cpu cpu = static_cast<op_cpu>(header.cpu_type);

	string str;
	if (want_xml) {
		string cpu_name = op_get_cpu_name(cpu);

		str = xml_utils::get_profile_header(cpu_name, header.cpu_speed);
	} else {
		str += string("CPU: ") + op_get_cpu_type_str(cpu);
		str += ", speed ";

		ostringstream ss;
		ss << header.cpu_speed;
		str += ss.str() + " MHz (estimated)";
	}
	return str;
}
