blob: 24a81fb1262fbd3ba4c2714b711ac506e2dbe4a9 [file] [log] [blame]
/*!
##############################################################################
# Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
##############################################################################
*/
// Implements the trace plugin interface for the MTI interface to trace
// source data from Arm FVP.
#include "MTI/PluginInterface.h"
#include "MTI/PluginFactory.h"
#include "MTI/PluginInstance.h"
#include "MTI/ModelTraceInterface.h"
#include "MTI/ParameterInterface.h"
#include "plugin_utils.h"
#include "trace_sources.h"
#include <errno.h>
#include <string>
#include <algorithm>
#include <cstdio>
#include <sstream>
#include <vector>
#include <map>
#include <typeinfo>
#include <typeindex>
#include <utility>
#include "SimpleCADI.h"
#ifdef SG_MODEL_BUILD
#include "builddata.h"
#define PLUGIN_VERSION FULL_VERSION_STRING
#else
#define PLUGIN_VERSION "unreleased"
#endif
enum plugin_param_t
{
TRACE_FILE_PREFIX,
TRACE_MODE,
TOTAL_PARAMETERS
};
using namespace eslapi;
using namespace MTI;
using namespace std;
// Implements the plugin interface for trace coverage
// Class used to return a static object CAInterface. CAInterface provides a
// basis for a software model built around ’components’ and ’interfaces’.
// A component provides concrete implementations of one or more interfaces.
// Interfaces are identified by a string name (of type if_name_t), and an
// integer revision (type if_rev_t). A higher revision number indicates a newer
// revision of the same interface.
class ThePluginFactory :public PluginFactory
{
public:
virtual CAInterface *ObtainInterface(if_name_t ifName,
if_rev_t minRev,
if_rev_t * actualRev);
virtual uint32_t GetNumberOfParameters();
virtual eslapi::CADIReturn_t
GetParameterInfos(eslapi::CADIParameterInfo_t *parameter_info_list);
virtual CAInterface *Instantiate(const char *instance_name,
uint32_t number_of_parameters,
eslapi::CADIParameterValue_t *parameter_values);
virtual void Release();
virtual const char *GetType() const { return "CoverageTrace"; }
virtual const char *GetVersion() const { return PLUGIN_VERSION; }
};
static ThePluginFactory *GetThePluginFactory();
class CoverageTrace :
public ParameterInterface,
public PluginInstance
{
public:
virtual CAInterface * ObtainInterface(if_name_t ifName,
if_rev_t minRev,
if_rev_t * actualRev);
CoverageTrace(const char *instance_name, const char *trace_file_prefix,
int _mode);
~CoverageTrace();
/** This is to associate a plugin with a simulation instance. Exactly one
* simulation must be registered.
* */
virtual eslapi::CADIReturn_t RegisterSimulation(eslapi::CAInterface
*simulation);
// This is called before the plugin .dll/.so is unloaded and should allow
// the plugin to do it's cleanup.
virtual void Release();
void Save(void);
virtual const char *GetName() const;
virtual eslapi::CADIReturn_t GetParameterInfos(uint32_t start_index,
uint32_t desired_num_of_params,
uint32_t* actual_num_of_params,
eslapi::CADIParameterInfo_t* params);
virtual eslapi::CADIReturn_t GetParameterInfo(const char* parameterName,
eslapi::CADIParameterInfo_t* param);
virtual eslapi::CADIReturn_t GetParameterValues(uint32_t parameter_count,
uint32_t* actual_num_of_params_read,
eslapi::CADIParameterValue_t* param_values_out);
virtual eslapi::CADIReturn_t SetParameterValues(uint32_t parameter_count,
eslapi::CADIParameterValue_t* parameters,
eslapi::CADIFactoryErrorMessage_t* error);
ModeChangeTraceContext *mode_change;
private:
std::string instance_name;
bool Error(const char *);
vector<TraceComponentContext*> trace_components;
std::string trace_file_prefix;
int trace_mode;
};
CAInterface *CoverageTrace::ObtainInterface(if_name_t ifName,
if_rev_t minRev,
if_rev_t * actualRev)
{
printf("CoverageTrace::ObtainInterface\n");
// If someone is asking for the matching interface
if((strcmp(ifName,PluginInstance::IFNAME()) == 0) &&
// and the revision of this interface implementation is
(minRev <= PluginInstance::IFREVISION()))
// at least what is being asked for
{
if (actualRev) // Make sure this is not a NULL pointer
*actualRev = PluginInstance::IFREVISION();
return dynamic_cast<PluginInstance *>(this);
}
if((strcmp(ifName, CAInterface::IFNAME()) == 0) &&
minRev <= CAInterface::IFREVISION())
{
if (actualRev != NULL)
*actualRev = CAInterface::IFREVISION();
return dynamic_cast<CAInterface *>(dynamic_cast<PluginInstance *>(this));
}
if((strcmp(ifName, ParameterInterface::IFNAME()) == 0) &&
minRev <= ParameterInterface::IFREVISION())
{
if (actualRev != NULL)
*actualRev = ParameterInterface::IFREVISION();
return dynamic_cast<ParameterInterface *>(this);
}
printf("CoverageTrace::ObtainInterface Failed!\n");
return NULL;
}
CoverageTrace::CoverageTrace(const char *instance_name_,
const char *trace_file_prefix_, int _mode) :
instance_name(instance_name_),
trace_file_prefix(trace_file_prefix_),
trace_mode(_mode)
{
printf("CoverageTrace::CoverageTrace\n");
}
CoverageTrace::~CoverageTrace()
{
printf("CoverageTrace::~CoverageTrace\n");
}
bool
CoverageTrace::Error(const char *msg)
{
fprintf(stderr, "%s\n", msg);
return false;
}
// Method that registers the simulation traces events. In this case registers
// for trace sources with the 'INST' name.
CADIReturn_t
CoverageTrace::RegisterSimulation(CAInterface *ca_interface)
{
printf("CoverageTrace::RegisterSimulation\n");
if (!ca_interface) {
Error("Received CAInterface NULL pointer.");
return CADI_STATUS_IllegalArgument;
}
std::stringstream ss;
SystemTraceInterface *sys_if =
ca_interface->ObtainPointer<SystemTraceInterface>();
if (sys_if == 0) {
Error("Got a NULL SystemTraceInterface.");
return CADI_STATUS_GeneralError;
}
for(SystemTraceInterface::TraceComponentIndex tci=0;
tci < sys_if->GetNumOfTraceComponents(); ++tci) {
const char* tpath = sys_if->GetComponentTracePath(tci);
CAInterface *caif = sys_if->GetComponentTrace(tci);
ComponentTraceInterface *cti =
caif->ObtainPointer<ComponentTraceInterface>();
InstructionTraceContext *inst_cont = NULL;
MTI::EventClass * event = NULL;
if (cti == 0) {
Error("Could not get TraceInterface for component.");
continue;
}
if (cti->GetTraceSource("INST") != 0) {
TraceComponentContext *trace_component = new
TraceComponentContext(tpath);
// To register a new trace source the arguments are the
// name of the trace source followed by a vector of
// pairs of (field name,field type).
inst_cont = new InstructionTraceContext(
"INST",
{ {"PC", u32},
{"SIZE", u32}}
);
inst_cont->nb_insts = 0;
event = inst_cont->CreateEvent(&cti, inst_cont->Callback);
event->UnregisterCallback(inst_cont->Callback, inst_cont);
trace_component->AddTraceSource(inst_cont);
trace_components.push_back(trace_component);
}
if (cti->GetTraceSource("MODE_CHANGE") != 0) {
MTI::EventClass * mode_event = NULL;
if(!event) {
Error("Could not set mode_change event");
continue;
}
// To register a new trace source the arguments are the
// name of the trace source followed by a vector of
// pairs of (field name,field type).
this->mode_change = new ModeChangeTraceContext(
"MODE_CHANGE",
{ {"MODE", u8},
{"NON_SECURE", u8}
}
);
mode_event = this->mode_change->CreateEvent(&cti, this->mode_change->Callback);
this->mode_change->event = event;
this->mode_change->itc = inst_cont;
this->mode_change->mode_mask = trace_mode;
mode_event->RegisterCallback(this->mode_change->Callback, mode_change);
}
}
return CADI_STATUS_OK;
}
// This is called before the plugin .dll/.so is unloaded and should allow the
// plugin to do it's cleanup.
void
CoverageTrace::Release()
{
printf("CoverageTrace::Release\n");
// We can dump our data now
this->Save();
}
void
CoverageTrace::Save(void)
{
int error = 0;
char* fname;
int ret;
std::vector<TraceComponentContext*>::iterator tcc;
for (tcc = trace_components.begin(); tcc < trace_components.end(); ++tcc) {
TraceComponentContext *tcont = *tcc;
// Print some overall stats
InstructionTraceContext* rtc = (InstructionTraceContext*)
tcont->trace_sources["INST"];
printf("Trace path: %s\n", tcont->trace_path.c_str());
// Construct a trace file name
int status = asprintf(&fname, "%s-%s.log",
this->trace_file_prefix.c_str(),
tcont->trace_path.c_str());
if ( status == -1)
{
printf("Error in asprintf: %d\n", status);
printf("Error description is : %s\n", strerror(errno));
}
// Open it
FILE* fp = fopen(fname, "w");
if (fp == NULL) {
fprintf(stderr, "Can't open file %s for writing.\n", fname);
error = 1;
break;
}
InstStatMap::iterator map_it;
// Dump the detailed stats
for (map_it = rtc->stats.begin(); map_it != rtc->stats.end();
++map_it) {
fprintf(fp, "%08x %lu %lu\n", (unsigned int)map_it->first,
(unsigned long)map_it->second.cnt,
(unsigned long)map_it->second.size);
}
// Close the file
ret = fclose(fp);
if (ret != 0) {
fprintf(stderr, "Failed to close %s: %s.", fname, strerror(errno));
error = 1;
break;
}
free(fname);
}
printf("Everything saved\n");
if (error != 0)
delete this;
}
const char *
CoverageTrace::GetName() const
{
printf("CoverageTrace::GetName\n");
return instance_name.c_str();
}
CADIReturn_t CoverageTrace::GetParameterInfos(uint32_t start_index,
uint32_t desired_num_of_params,
uint32_t* actual_num_of_params,
CADIParameterInfo_t* params)
{
*actual_num_of_params = GetThePluginFactory()->GetNumberOfParameters();
return GetThePluginFactory()->GetParameterInfos(params);
}
CADIReturn_t CoverageTrace::GetParameterInfo(const char* parameterName,
CADIParameterInfo_t* param)
{
uint32_t num_of_params = GetThePluginFactory()->GetNumberOfParameters();
CADIParameterInfo_t* plugin_parameters = NULL;
GetThePluginFactory()->GetParameterInfos(plugin_parameters);
if (param == nullptr)
{
return CADI_STATUS_IllegalArgument;
}
printf("Reading parameter info %s \n", parameterName);
for (uint32_t i = 0; i < num_of_params; ++i)
{
if (strcmp(plugin_parameters[i].name, parameterName) == 0)
{
*param = plugin_parameters[i];
return CADI_STATUS_OK;
}
}
*param = plugin_parameters[0];
return CADI_STATUS_OK;
}
CADIReturn_t CoverageTrace::GetParameterValues(uint32_t parameter_count,
uint32_t* actual_num_of_params_read,
CADIParameterValue_t *param_values_out)
{
if (param_values_out == nullptr || actual_num_of_params_read == nullptr)
{
return CADI_STATUS_IllegalArgument;
}
*actual_num_of_params_read = 0;
for (uint32_t i = 0; i < parameter_count; ++i)
{
CADIParameterValue_t &param_value = param_values_out[i];
switch (param_value.parameterID)
{
case TRACE_FILE_PREFIX:
strncpy(param_value.stringValue,
this->trace_file_prefix.c_str(),
sizeof(param_value.stringValue));
break;
case TRACE_MODE:
param_value.intValue = this->mode_change->mode_mask;
break;
default: // unknown ID
*actual_num_of_params_read = i;
return CADI_STATUS_IllegalArgument;
}
}
*actual_num_of_params_read = parameter_count;
return CADI_STATUS_OK;
}
CADIReturn_t CoverageTrace::SetParameterValues(uint32_t parameter_count,
CADIParameterValue_t* parameters,
CADIFactoryErrorMessage_t* error)
{
for (uint32_t i = 0; i < parameter_count; ++i)
{
CADIParameterValue_t &parameter = parameters[i];
switch(parameter.parameterID)
{
case TRACE_FILE_PREFIX:
this->trace_file_prefix = parameter.stringValue;
this->Save();
break;
case TRACE_MODE:
this->mode_change->mode_mask = parameter.intValue;
break;
default:
;
break;
}
}
return CADI_STATUS_OK;
}
// Allows a client to obtain a reference to any of the interfaces that the
// component implements. The client specifies the id and revision of the
// interface that it wants to request. The component can return NULL if it
// doesn’t implement that interface, or only implements a lower revision.
// The client in this case is the Arm FVP model.
CAInterface *ThePluginFactory::ObtainInterface(if_name_t ifName,
if_rev_t minRev,
if_rev_t * actualRev)
{
printf("ThePluginFactory::ObtainInterface\n");
// If someone is asking for the matching interface
if((strcmp(ifName,IFNAME()) == 0) &&
// and the revision of this interface implementation is
(minRev <= IFREVISION()))
// at least what is being asked for
{
if (actualRev) // Make sure this is not a NULL pointer
*actualRev = IFREVISION();
return static_cast<ThePluginFactory *>(this);
}
if((strcmp(ifName, CAInterface::IFNAME()) == 0) &&
minRev <= CAInterface::IFREVISION())
{
if (actualRev) // Make sure this is not a NULL pointer
*actualRev = CAInterface::IFREVISION();
return static_cast<CAInterface *>(this);
}
return NULL;
}
uint32_t ThePluginFactory::GetNumberOfParameters()
{
printf("ThePluginFactory::GetNumberOfParameters\n");
return TOTAL_PARAMETERS;
}
eslapi::CADIReturn_t
ThePluginFactory::GetParameterInfos(
eslapi::CADIParameterInfo_t *parameter_info_list)
{
printf("ThePluginFactory::GetParameterInfos\n");
parameter_info_list[0] = CADIParameterInfo_t(
TRACE_FILE_PREFIX, "trace-file-prefix", CADI_PARAM_STRING,
"Prefix of the trace files.", true, 0, 0, 0, "covtrace");
parameter_info_list[1] = CADIParameterInfo_t(
TRACE_MODE, "trace-mode", CADI_PARAM_INT,
"Selects which modes to trace.", true, 0, 0xffffffff, 0xffffffff, 0);
return CADI_STATUS_OK;
}
// Method that creates a new instance of the trace plugin
CAInterface *ThePluginFactory::Instantiate(const char *instance_name,
uint32_t param_nb,
eslapi::CADIParameterValue_t *values)
{
printf("ThePluginFactory::Instantiate\n");
const char *trace_file_prefix = 0;
int mode_value = 0xffffffff;
printf("CoverageTrace: number of params: %d\n", param_nb);
for (uint32_t i = 0; i < param_nb; ++i) {
if (values[i].parameterID == TRACE_FILE_PREFIX) {
trace_file_prefix = values[i].stringValue;
} else if (values[i].parameterID == TRACE_MODE) {
mode_value = values[i].intValue;
} else {
printf("\tCoverageTrace: got unexpected param %d\n",
values[i].parameterID);
}
}
return (PluginInstance*)new CoverageTrace(instance_name, trace_file_prefix,
mode_value);
}
void ThePluginFactory::Release()
{
printf("ThePluginFactory::Release\n");
}
static ThePluginFactory factory_instance;
// Entry point for the instantiation of the plugin.
// Returns a pointer to an static object to create the interface for the
// plugin.
CAInterface *GetCAInterface()
{
printf("********->GetCAInterface\n");
return &factory_instance;
}
static ThePluginFactory *GetThePluginFactory()
{
return &factory_instance;
}
// End of file CoverageTrace.cpp