arch-arm: Add support for Tarmac trace generation

This patch introduces the TarmacTracer: an instruction tracer which
allows to dump a gem5 execution trace in Tarmac format [1]. The new
tracer is supporting either Tarmac and TarmacV8 format specifications.
Not every traceable information has been implemented:

Implemented Trace Type:
    Instruction Trace
    Register Trace
    Processor Memory Access Trace

Unimplemented Trace Type:
    Program Flow Trace
    Event Trace
    Memory Bus Trace

[1]: https://developer.arm.com/docs/dui0845/f/tarmac-trace-file-format

Change-Id: I8799d8e5852e868673f728971db3fe8c63961f5e
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/9382
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
This commit is contained in:
Giacomo Travaglini
2018-03-14 17:26:06 +00:00
parent 2d1add2d5d
commit 4a66b5f7f8
8 changed files with 1372 additions and 0 deletions

View File

@@ -42,3 +42,6 @@ if env['TARGET_ISA'] == 'arm':
SimObject('TarmacTrace.py')
Source('tarmac_base.cc')
Source('tarmac_parser.cc')
Source('tarmac_tracer.cc')
Source('tarmac_record.cc')
Source('tarmac_record_v8.cc')

View File

@@ -64,3 +64,14 @@ class TarmacParser(InstTracer):
ignore_mem_addr = Param.AddrRange(AddrRange(0, size=0),
"Range of unverifiable memory addresses")
class TarmacTracer(InstTracer):
type = 'TarmacTracer'
cxx_class = 'Trace::TarmacTracer'
cxx_header = "arch/arm/tracers/tarmac_tracer.hh"
start_tick = Param.Tick(0,
"tracing starts when the tick time gets this value")
end_tick = Param.Tick(MaxTick,
"tracing ends when the tick time gets this value")

View File

@@ -0,0 +1,457 @@
/*
* Copyright (c) 2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Giacomo Travaglini
*/
#include "arch/arm/tracers/tarmac_record.hh"
#include "arch/arm/insts/static_inst.hh"
#include "tarmac_tracer.hh"
namespace Trace {
// TARMAC Instruction Record static variables
uint64_t TarmacTracerRecord::TraceInstEntry::instCount = 0;
std::string
iSetStateToStr(TarmacBaseRecord::ISetState isetstate)
{
switch (isetstate) {
case TarmacBaseRecord::ISET_ARM:
return "A";
case TarmacBaseRecord::ISET_THUMB:
return "T";
case TarmacBaseRecord::ISET_A64:
return "O";
default:
return "Unsupported";
}
}
std::string
opModeToStr(OperatingMode opMode)
{
switch (opMode) {
case MODE_EL0T:
return "EL0t";
case MODE_EL1T:
return "EL1t";
case MODE_EL1H:
return "EL1h";
case MODE_EL2T:
return "EL2t";
case MODE_EL2H:
return "EL2h";
case MODE_EL3T:
return "EL3t";
case MODE_EL3H:
return "EL3h";
case MODE_USER:
return "usr";
case MODE_FIQ:
return "fiq";
case MODE_IRQ:
return "irq";
case MODE_SVC:
return "svc";
case MODE_MON:
return "mon";
case MODE_ABORT:
return "abt";
case MODE_HYP:
return "hyp";
case MODE_UNDEFINED:
return "und";
case MODE_SYSTEM:
return "sys";
default:
return "Unsupported";
}
}
// TarmacTracerRecord ctor
TarmacTracerRecord::TarmacTracerRecord(Tick _when, ThreadContext *_thread,
const StaticInstPtr _staticInst,
PCState _pc,
TarmacTracer& _tracer,
const StaticInstPtr _macroStaticInst)
: TarmacBaseRecord(_when, _thread, _staticInst,
_pc, _macroStaticInst),
tracer(_tracer)
{
}
TarmacTracerRecord::TraceInstEntry::TraceInstEntry(
const TarmacContext& tarmCtx,
bool predicate)
: InstEntry(tarmCtx.thread, tarmCtx.pc, tarmCtx.staticInst, predicate)
{
secureMode = inSecureState(tarmCtx.thread);
auto arm_inst = static_cast<const ArmStaticInst*>(
tarmCtx.staticInst.get()
);
// Get the instruction size as a number of bits:
// (multiply byte size by 8)
instSize = (arm_inst->instSize() << 3);
// Mask the opcode using the instruction size: the
// opcode field will otherwise be 32 bit wide even
// for 16bit (Thumb) instruction.
opcode = arm_inst->encoding();
// Update the instruction count: number of executed
// instructions.
instCount++;
}
TarmacTracerRecord::TraceMemEntry::TraceMemEntry(
const TarmacContext& tarmCtx,
uint8_t _size, Addr _addr, uint64_t _data)
: MemEntry(_size, _addr, _data),
loadAccess(tarmCtx.staticInst->isLoad())
{
}
TarmacTracerRecord::TraceRegEntry::TraceRegEntry(
const TarmacContext& tarmCtx,
const RegId& reg)
: RegEntry(tarmCtx.pc),
regValid(false),
regClass(reg.classValue()),
regRel(reg.index())
{
}
void
TarmacTracerRecord::TraceRegEntry::update(
const TarmacContext& tarmCtx
)
{
// Fill the register entry data, according to register
// class.
switch (regClass) {
case CCRegClass:
updateCC(tarmCtx, regRel);
break;
case FloatRegClass:
updateFloat(tarmCtx, regRel);
break;
case IntRegClass:
updateInt(tarmCtx, regRel);
break;
case MiscRegClass:
updateMisc(tarmCtx, regRel);
break;
default:
// If unsupported format, do nothing: non updating
// the register will prevent it to be printed.
break;
}
}
void
TarmacTracerRecord::TraceRegEntry::updateMisc(
const TarmacContext& tarmCtx,
RegIndex regRelIdx
)
{
auto thread = tarmCtx.thread;
regValid = true;
regName = miscRegName[regRelIdx];
valueLo = thread->readMiscRegNoEffect(regRelIdx);
// If it is the CPSR:
// update the value of the CPSR register and add
// the CC flags on top of the value
if (regRelIdx == MISCREG_CPSR) {
CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
cpsr.nz = thread->readCCReg(CCREG_NZ);
cpsr.c = thread->readCCReg(CCREG_C);
cpsr.v = thread->readCCReg(CCREG_V);
cpsr.ge = thread->readCCReg(CCREG_GE);
// update the entry value
valueLo = cpsr;
}
}
void
TarmacTracerRecord::TraceRegEntry::updateCC(
const TarmacContext& tarmCtx,
RegIndex regRelIdx
)
{
auto thread = tarmCtx.thread;
regValid = true;
regName = ccRegName[regRelIdx];
valueLo = thread->readCCReg(regRelIdx);
}
void
TarmacTracerRecord::TraceRegEntry::updateFloat(
const TarmacContext& tarmCtx,
RegIndex regRelIdx
)
{
auto thread = tarmCtx.thread;
regValid = true;
regName = "f" + std::to_string(regRelIdx);
valueLo = thread->readFloatReg(regRelIdx);
}
void
TarmacTracerRecord::TraceRegEntry::updateInt(
const TarmacContext& tarmCtx,
RegIndex regRelIdx
)
{
auto thread = tarmCtx.thread;
// Reading operating mode from CPSR.
// This is needed when printing the register name in case
// of banked register (e.g. lr_svc)
CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
OperatingMode mode = (OperatingMode)(uint8_t)cpsr.mode;
std::string reg_suffix;
if (mode != MODE_USER) {
reg_suffix = "_" + opModeToStr(mode);
}
regValid = true;
switch (regRelIdx) {
case PCReg:
regName = "pc";
break;
case StackPointerReg:
regName = "sp" + reg_suffix ;
break;
case FramePointerReg:
regName = "fp" + reg_suffix;
break;
case ReturnAddressReg:
regName = "lr" + reg_suffix;
break;
default:
regName = "r" + std::to_string(regRelIdx);
break;
}
valueLo = thread->readIntReg(regRelIdx);
}
void
TarmacTracerRecord::addInstEntry(std::vector<InstPtr>& queue,
const TarmacContext& tarmCtx)
{
// Generate an instruction entry in the record and
// add it to the Instruction Queue
queue.push_back(
m5::make_unique<TraceInstEntry>(tarmCtx, predicate)
);
}
void
TarmacTracerRecord::addMemEntry(std::vector<MemPtr>& queue,
const TarmacContext& tarmCtx)
{
// Generate a memory entry in the record if the record
// implies a valid memory access, and add it to the
// Memory Queue
if (getMemValid()) {
queue.push_back(
m5::make_unique<TraceMemEntry>(tarmCtx,
static_cast<uint8_t>(getSize()),
getAddr(), getIntData())
);
}
}
void
TarmacTracerRecord::addRegEntry(std::vector<RegPtr>& queue,
const TarmacContext& tarmCtx)
{
// Generate an entry for every ARM register being
// written by the current instruction
for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
RegId reg_id = staticInst->destRegIdx(reg);
// Creating a single register change entry
auto single_reg = genRegister<TraceRegEntry>(tarmCtx, reg_id);
// Copying the entry and adding it to the "list"
// of entries to be dumped to trace.
queue.push_back(
m5::make_unique<TraceRegEntry>(single_reg)
);
}
// Gem5 is treating CPSR flags as separate registers (CC registers),
// in contrast with Tarmac specification: we need to merge the gem5 CC
// entries altogether with the CPSR register and produce a single entry.
mergeCCEntry<TraceRegEntry>(queue, tarmCtx);
}
void
TarmacTracerRecord::dump()
{
// Generate and print all the record's entries.
auto &instQueue = tracer.instQueue;
auto &memQueue = tracer.memQueue;
auto &regQueue = tracer.regQueue;
const TarmacContext tarmCtx(
thread,
staticInst->isMicroop()? macroStaticInst : staticInst,
pc
);
if (!staticInst->isMicroop()) {
// Current instruction is NOT a micro-instruction:
// Generate Tarmac entries and dump them immediately
// Generate Tarmac entries and add them to the respective
// queues.
addInstEntry(instQueue, tarmCtx);
addMemEntry(memQueue, tarmCtx);
addRegEntry(regQueue, tarmCtx);
// Flush (print) any queued entry.
flushQueues(instQueue, memQueue, regQueue);
} else {
// Current instruction is a micro-instruction:
// save micro entries into dedicated queues and flush them
// into the tracefile only when the MACRO-instruction
// has completed.
if (staticInst->isFirstMicroop()) {
addInstEntry(instQueue, tarmCtx);
}
addRegEntry(regQueue, tarmCtx);
addMemEntry(memQueue, tarmCtx);
if (staticInst->isLastMicroop()) {
// Flush (print) any queued entry.
flushQueues(instQueue, memQueue, regQueue);
}
}
}
template<typename Queue>
void
TarmacTracerRecord::flushQueues(Queue& queue)
{
std::ostream &outs = Trace::output();
for (const auto &single_entry : queue) {
single_entry->print(outs);
}
queue.clear();
}
template<typename Queue, typename... Args>
void
TarmacTracerRecord::flushQueues(Queue& queue, Args & ... args)
{
flushQueues(queue);
flushQueues(args...);
}
void
TarmacTracerRecord::TraceInstEntry::print(
std::ostream& outs,
int verbosity,
const std::string &prefix) const
{
// Pad the opcode
std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
// Print the instruction record formatted according
// to the Tarmac specification
ccprintf(outs, "%s clk %s (%u) %08x %s %s %s_%s : %s\n",
curTick(), /* Tick time */
taken? "IT" : "IS", /* Instruction taken/skipped */
instCount, /* Instruction count */
addr, /* Instruction address */
opcode_str, /* Instruction opcode */
iSetStateToStr(isetstate), /* Instruction Set */
opModeToStr(mode), /* Exception level */
secureMode? "s" : "ns", /* Security */
disassemble); /* Instruction disass */
}
void
TarmacTracerRecord::TraceMemEntry::print(
std::ostream& outs,
int verbosity,
const std::string &prefix) const
{
// Print the memory record formatted according
// to the Tarmac specification
ccprintf(outs, "%s clk M%s%d %08x %0*x\n",
curTick(), /* Tick time */
loadAccess? "R" : "W", /* Access type */
size, /* Access size */
addr, /* Memory address */
size*2, /* Padding with access size */
data); /* Memory data */
}
void
TarmacTracerRecord::TraceRegEntry::print(
std::ostream& outs,
int verbosity,
const std::string &prefix) const
{
// Print the register record formatted according
// to the Tarmac specification
if (regValid)
ccprintf(outs, "%s clk R %s %08x\n",
curTick(), /* Tick time */
regName, /* Register name */
valueLo); /* Register value */
}
} // namespace Trace

View File

@@ -0,0 +1,265 @@
/*
* Copyright (c) 2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Giacomo Travaglini
*/
/**
* @file: The file contains the informations used to generate records
* for the pre-ARMv8 cores.
*/
#ifndef __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
#define __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
#include "arch/arm/tracers/tarmac_base.hh"
#include "base/printable.hh"
#include "config/the_isa.hh"
#include "cpu/reg_class.hh"
#include "cpu/static_inst.hh"
namespace Trace {
class TarmacContext;
class TarmacTracer;
/**
* Returns the string representation of the instruction set being
* currently run according to the Tarmac format.
*
* @param isetstate: enum variable (ISetState) specifying an ARM
* instruction set.
* @return instruction set in string format.
*/
std::string
iSetStateToStr(TarmacBaseRecord::ISetState isetstate);
/**
* Returns the string representation of the ARM Operating Mode
* (CPSR.M[3:0] field) according to the Tarmac format.
*
* @param opMode: ARM operating mode.
* @return operating mode in string format.
*/
std::string
opModeToStr(ArmISA::OperatingMode opMode);
/**
* TarmacTracer Record:
* Record generated by the TarmacTracer for every executed instruction.
* The record is composed by a set of entries, matching the tracing
* capabilities provided by the Tarmac specifications:
*
* - Instruction Entry
* - Register Entry
* - Memory Entry
*/
class TarmacTracerRecord : public TarmacBaseRecord
{
public:
/** Instruction Entry */
struct TraceInstEntry: public InstEntry, Printable
{
TraceInstEntry(const TarmacContext& tarmCtx, bool predicate);
virtual void print(std::ostream& outs,
int verbosity = 0,
const std::string &prefix = "") const override;
protected:
/** Number of instructions being traced */
static uint64_t instCount;
/** True if instruction is executed in secure mode */
bool secureMode;
/**
* Instruction size:
* 16 for 16-bit Thumb Instruction
* 32 otherwise (ARM and BigThumb)
*/
uint8_t instSize;
};
/** Register Entry */
struct TraceRegEntry: public RegEntry, Printable
{
public:
TraceRegEntry(const TarmacContext& tarmCtx, const RegId& reg);
/**
* This updates the register entry using the update table. It is
* a required step after the register entry generation.
* If unupdated, the entry will be marked as invalid.
* The entry update cannot be done automatically at TraceRegEntry
* construction: the entries are extended by consequent Tarmac
* Tracer versions (like V8), and virtual functions should
* be avoided during construction.
*/
void update(const TarmacContext& tarmCtx);
virtual void print(std::ostream& outs,
int verbosity = 0,
const std::string &prefix = "") const override;
protected:
/** Register update functions. */
virtual void
updateMisc(const TarmacContext& tarmCtx, RegIndex regRelIdx);
virtual void
updateCC(const TarmacContext& tarmCtx, RegIndex regRelIdx);
virtual void
updateFloat(const TarmacContext& tarmCtx, RegIndex regRelIdx);
virtual void
updateInt(const TarmacContext& tarmCtx, RegIndex regRelIdx);
public:
/** True if register entry is valid */
bool regValid;
/** Register class */
RegClass regClass;
/** Register arch number */
RegIndex regRel;
/** Register name to be printed */
std::string regName;
};
/** Memory Entry */
struct TraceMemEntry: public MemEntry, Printable
{
public:
TraceMemEntry(const TarmacContext& tarmCtx,
uint8_t _size, Addr _addr, uint64_t _data);
virtual void print(std::ostream& outs,
int verbosity = 0,
const std::string &prefix = "") const override;
protected:
/** True if memory access is a load */
bool loadAccess;
};
public:
TarmacTracerRecord(Tick _when, ThreadContext *_thread,
const StaticInstPtr _staticInst, TheISA::PCState _pc,
TarmacTracer& _tracer,
const StaticInstPtr _macroStaticInst = NULL);
virtual void dump() override;
using InstPtr = std::unique_ptr<TraceInstEntry>;
using MemPtr = std::unique_ptr<TraceMemEntry>;
using RegPtr = std::unique_ptr<TraceRegEntry>;
protected:
/** Generates an Entry for the executed instruction. */
virtual void addInstEntry(std::vector<InstPtr>& queue,
const TarmacContext& ptr);
/** Generates an Entry for every triggered memory access */
virtual void addMemEntry(std::vector<MemPtr>& queue,
const TarmacContext& ptr);
/** Generate an Entry for every register being written. */
virtual void addRegEntry(std::vector<RegPtr>& queue,
const TarmacContext& ptr);
protected:
/** Generate and update a register entry. */
template<typename RegEntry>
RegEntry
genRegister(const TarmacContext& tarmCtx, const RegId& reg)
{
RegEntry single_reg(tarmCtx, reg);
single_reg.update(tarmCtx);
return single_reg;
}
template<typename RegEntry>
void
mergeCCEntry(std::vector<RegPtr>& queue, const TarmacContext& tarmCtx)
{
// Find all CC Entries and move them at the end of the queue
auto it = std::remove_if(
queue.begin(), queue.end(),
[] (RegPtr& reg) ->bool { return (reg->regClass == CCRegClass); }
);
if (it != queue.end()) {
// Remove all CC Entries.
queue.erase(it, queue.end());
auto is_cpsr = [] (RegPtr& reg) ->bool
{
return (reg->regClass == MiscRegClass) &&
(reg->regRel == ArmISA::MISCREG_CPSR);
};
// Looking for the presence of a CPSR register entry.
auto cpsr_it = std::find_if(
queue.begin(), queue.end(), is_cpsr
);
// If CPSR entry not present, generate one
if (cpsr_it == queue.end()) {
RegId reg(MiscRegClass, ArmISA::MISCREG_CPSR);
queue.push_back(
m5::make_unique<RegEntry>(
genRegister<RegEntry>(tarmCtx, reg))
);
}
}
}
/** Flush queues to the trace output */
template<typename Queue>
void flushQueues(Queue& queue);
template<typename Queue, typename... Args>
void flushQueues(Queue& queue, Args & ... args);
protected:
/** Reference to tracer */
TarmacTracer& tracer;
};
} // namespace Trace
#endif // __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__

View File

@@ -0,0 +1,248 @@
/*
* Copyright (c) 2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Giacomo Travaglini
*/
#include "arch/arm/tracers/tarmac_record_v8.hh"
#include "arch/arm/insts/static_inst.hh"
#include "arch/arm/tlb.hh"
#include "arch/arm/tracers/tarmac_tracer.hh"
namespace Trace {
TarmacTracerRecordV8::TraceInstEntryV8::TraceInstEntryV8(
const TarmacContext& tarmCtx,
bool predicate)
: TraceInstEntry(tarmCtx, predicate),
TraceEntryV8(tarmCtx.tarmacCpuName()),
paddr(0),
paddrValid(false)
{
const auto thread = tarmCtx.thread;
// Evaluate physical address
TheISA::TLB* dtb = static_cast<TLB*>(thread->getDTBPtr());
paddrValid = dtb->translateFunctional(thread, addr, paddr);
}
TarmacTracerRecordV8::TraceMemEntryV8::TraceMemEntryV8(
const TarmacContext& tarmCtx,
uint8_t _size, Addr _addr, uint64_t _data)
: TraceMemEntry(tarmCtx, _size, _addr, _data),
TraceEntryV8(tarmCtx.tarmacCpuName()),
paddr(_addr)
{
const auto thread = tarmCtx.thread;
// Evaluate physical address
TheISA::TLB* dtb = static_cast<TLB*>(thread->getDTBPtr());
dtb->translateFunctional(thread, addr, paddr);
}
TarmacTracerRecordV8::TraceRegEntryV8::TraceRegEntryV8(
const TarmacContext& tarmCtx,
const RegId& reg)
: TraceRegEntry(tarmCtx, reg),
TraceEntryV8(tarmCtx.tarmacCpuName()),
regWidth(64)
{
}
void
TarmacTracerRecordV8::TraceRegEntryV8::updateInt(
const TarmacContext& tarmCtx,
RegIndex regRelIdx
)
{
// Do not trace pseudo register accesses: invalid
// register entry.
if (regRelIdx > NUM_ARCH_INTREGS) {
regValid = false;
return;
}
TraceRegEntry::updateInt(tarmCtx, regRelIdx);
if ((regRelIdx != PCReg) || (regRelIdx != StackPointerReg) ||
(regRelIdx != FramePointerReg) || (regRelIdx != ReturnAddressReg)) {
const auto* arm_inst = static_cast<const ArmStaticInst*>(
tarmCtx.staticInst.get()
);
regWidth = (arm_inst->getIntWidth());
if (regWidth == 32) {
regName = "W" + std::to_string(regRelIdx);
} else {
regName = "X" + std::to_string(regRelIdx);
}
}
}
void
TarmacTracerRecordV8::TraceRegEntryV8::updateMisc(
const TarmacContext& tarmCtx,
RegIndex regRelIdx
)
{
TraceRegEntry::updateMisc(tarmCtx, regRelIdx);
// System registers are 32bit wide
regWidth = 32;
}
void
TarmacTracerRecordV8::addInstEntry(std::vector<InstPtr>& queue,
const TarmacContext& tarmCtx)
{
// Generate an instruction entry in the record and
// add it to the Instruction Queue
queue.push_back(
m5::make_unique<TraceInstEntryV8>(tarmCtx, predicate)
);
}
void
TarmacTracerRecordV8::addMemEntry(std::vector<MemPtr>& queue,
const TarmacContext& tarmCtx)
{
// Generate a memory entry in the record if the record
// implies a valid memory access, and add it to the
// Memory Queue
if (getMemValid()) {
queue.push_back(
m5::make_unique<TraceMemEntryV8>(tarmCtx,
static_cast<uint8_t>(getSize()),
getAddr(), getIntData())
);
}
}
void
TarmacTracerRecordV8::addRegEntry(std::vector<RegPtr>& queue,
const TarmacContext& tarmCtx)
{
// Generate an entry for every ARM register being
// written by the current instruction
for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
RegId reg_id = staticInst->destRegIdx(reg);
// Creating a single register change entry
auto single_reg = genRegister<TraceRegEntryV8>(tarmCtx, reg_id);
// Copying the entry and adding it to the "list"
// of entries to be dumped to trace.
queue.push_back(
m5::make_unique<TraceRegEntryV8>(single_reg)
);
}
// Gem5 is treating CPSR flags as separate registers (CC registers),
// in contrast with Tarmac specification: we need to merge the gem5 CC
// entries altogether with the CPSR register and produce a single entry.
mergeCCEntry<TraceRegEntryV8>(queue, tarmCtx);
}
void
TarmacTracerRecordV8::TraceInstEntryV8::print(
std::ostream& outs,
int verbosity,
const std::string &prefix) const
{
// If there is a valid vaddr->paddr translation, print the
// physical address, otherwise print the virtual address only.
std::string paddr_str = paddrValid? csprintf(":%012x",paddr) :
std::string();
// Pad the opcode.
std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
// Print the instruction record formatted according
// to the Tarmac specification
ccprintf(outs, "%s clk %s %s (%u) %08x%s %s %s %s_%s : %s\n",
curTick(), /* Tick time */
cpuName, /* Cpu name */
taken? "IT" : "IS", /* Instruction taken/skipped */
instCount, /* Instruction count */
addr, /* Instruction virt address */
paddr_str, /* Instruction phys address */
opcode_str, /* Instruction opcode */
iSetStateToStr(isetstate), /* Instruction Set */
opModeToStr(mode), /* Exception level */
secureMode? "s" : "ns", /* Security */
disassemble); /* Instruction disass */
}
void
TarmacTracerRecordV8::TraceMemEntryV8::print(
std::ostream& outs,
int verbosity,
const std::string &prefix) const
{
// Print the memory record formatted according
// to the Tarmac specification
ccprintf(outs, "%s clk %s M%s%d %08x:%012x %0*x\n",
curTick(), /* Tick time */
cpuName, /* Cpu name */
loadAccess? "R" : "W", /* Access type */
size, /* Access size */
addr, /* Virt Memory address */
paddr, /* Phys Memory address */
size*2, /* Padding with access size */
data); /* Memory data */
}
void
TarmacTracerRecordV8::TraceRegEntryV8::print(
std::ostream& outs,
int verbosity,
const std::string &prefix) const
{
// Print the register record formatted according
// to the Tarmac specification
if (regValid) {
ccprintf(outs, "%s clk %s R %s %0*x\n",
curTick(), /* Tick time */
cpuName, /* Cpu name */
regName, /* Register name */
regWidth >> 2, /* Register value padding */
valueLo); /* Register value */
}
}
} // namespace Trace

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Giacomo Travaglini
*/
/**
* @file: The file contains the informations used to generate records
* for ARMv8 cores.
*/
#ifndef __ARCH_ARM_TRACERS_TARMAC_RECORD_V8_HH__
#define __ARCH_ARM_TRACERS_TARMAC_RECORD_V8_HH__
#include "tarmac_record.hh"
namespace Trace {
/**
* TarmacTracer record for ARMv8 CPUs:
* The record is adding some data to the base TarmacTracer
* record.
*/
class TarmacTracerRecordV8 : public TarmacTracerRecord
{
public:
/**
* General data shared by all v8 entries
*/
struct TraceEntryV8
{
public:
TraceEntryV8(std::string _cpuName)
: cpuName(_cpuName)
{}
protected:
std::string cpuName;
};
/**
* Instruction entry for v8 records
*/
struct TraceInstEntryV8: public TraceInstEntry, TraceEntryV8
{
public:
TraceInstEntryV8(const TarmacContext& tarmCtx, bool predicate);
virtual void print(std::ostream& outs,
int verbosity = 0,
const std::string &prefix = "") const override;
protected:
Addr paddr;
bool paddrValid;
};
/**
* Register entry for v8 records
*/
struct TraceRegEntryV8: public TraceRegEntry, TraceEntryV8
{
public:
TraceRegEntryV8(const TarmacContext& tarmCtx, const RegId& reg);
virtual void print(std::ostream& outs,
int verbosity = 0,
const std::string &prefix = "") const override;
protected:
void updateInt(const TarmacContext& tarmCtx,
RegIndex regRelIdx) override;
void updateMisc(const TarmacContext& tarmCtx,
RegIndex regRelIdx) override;
uint8_t regWidth;
};
/**
* Memory Entry for V8
*/
struct TraceMemEntryV8: public TraceMemEntry, TraceEntryV8
{
public:
TraceMemEntryV8(const TarmacContext& tarmCtx,
uint8_t _size, Addr _addr, uint64_t _data);
virtual void print(std::ostream& outs,
int verbosity = 0,
const std::string &prefix = "") const override;
protected:
Addr paddr;
};
public:
TarmacTracerRecordV8(Tick _when, ThreadContext *_thread,
const StaticInstPtr _staticInst, TheISA::PCState _pc,
TarmacTracer& _parent,
const StaticInstPtr _macroStaticInst = NULL)
: TarmacTracerRecord(_when, _thread, _staticInst, _pc,
_parent, _macroStaticInst)
{}
protected:
/** Generates an Entry for the executed instruction. */
void addInstEntry(std::vector<InstPtr>& queue, const TarmacContext& ptr);
/** Generates an Entry for every memory access triggered */
void addMemEntry(std::vector<MemPtr>& queue, const TarmacContext& ptr);
/** Generate a Record for every register being written */
void addRegEntry(std::vector<RegPtr>& queue, const TarmacContext& ptr);
};
} // namespace Trace
#endif // __ARCH_ARM_TRACERS_TARMAC_RECORD_V8_HH__

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Giacomo Travaglini
*/
#include "tarmac_tracer.hh"
#include <string>
#include "arch/arm/system.hh"
#include "cpu/base.hh"
namespace Trace {
std::string
TarmacContext::tarmacCpuName() const
{
auto id = thread->getCpuPtr()->cpuId();
return "cpu" + std::to_string(id);
}
TarmacTracer::TarmacTracer(const Params *p)
: InstTracer(p),
startTick(p->start_tick),
endTick(p->end_tick)
{
// Wrong parameter setting: The trace end happens before the
// trace start.
panic_if(startTick > endTick,
"Tarmac start point: %lu is bigger than "
"Tarmac end point: %lu\n", startTick, endTick);
// By default cpu tracers in gem5 are not tracing faults
// (exceptions).
// This is not in compliance with the Tarmac specification:
// instructions like SVC, SMC, HVC have to be traced.
// Tarmac Tracer is then automatically enabling this behaviour.
setDebugFlag("ExecFaulting");
}
InstRecord *
TarmacTracer::getInstRecord(Tick when, ThreadContext *tc,
const StaticInstPtr staticInst,
TheISA::PCState pc,
const StaticInstPtr macroStaticInst)
{
// Check if we need to start tracing since we have passed the
// tick start point.
if (when < startTick || when > endTick)
return nullptr;
if (ArmSystem::highestELIs64(tc)) {
// TarmacTracerV8
return new TarmacTracerRecordV8(when, tc, staticInst, pc, *this,
macroStaticInst);
} else {
// TarmacTracer
return new TarmacTracerRecord(when, tc, staticInst, pc, *this,
macroStaticInst);
}
}
} // namespace Trace
Trace::TarmacTracer *
TarmacTracerParams::create()
{
return new Trace::TarmacTracer(this);
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Giacomo Travaglini
*/
/**
* @file: This file declares the interface of the Tarmac Tracer:
* the tracer based on the Tarmac specification.
*/
#ifndef __ARCH_ARM_TRACERS_TARMAC_TRACER_HH__
#define __ARCH_ARM_TRACERS_TARMAC_TRACER_HH__
#include "arch/arm/tracers/tarmac_record.hh"
#include "arch/arm/tracers/tarmac_record_v8.hh"
#include "params/TarmacTracer.hh"
#include "sim/insttracer.hh"
class ThreadContext;
namespace Trace {
/**
* This object type is encapsulating the informations needed by
* a Tarmac record to generate it's own entries.
*/
class TarmacContext
{
public:
TarmacContext(ThreadContext* _thread,
const StaticInstPtr _staticInst,
TheISA::PCState _pc)
: thread(_thread), staticInst(_staticInst), pc(_pc)
{}
std::string tarmacCpuName() const;
public:
ThreadContext* thread;
const StaticInstPtr staticInst;
TheISA::PCState pc;
};
/**
* Tarmac Tracer: this tracer generates a new Tarmac Record for
* every instruction being executed in gem5.
* The record is made by a collection of entries which are stored
* in the tracer queues.
*/
class TarmacTracer : public InstTracer
{
friend class TarmacTracerRecord;
friend class TarmacTracerRecordV8;
public:
typedef TarmacTracerParams Params;
TarmacTracer(const Params *p);
/**
* Generates a TarmacTracerRecord, depending on the Tarmac version.
* At the moment supported formats are:
* - Tarmac
* - TarmacV8
*/
InstRecord* getInstRecord(Tick when, ThreadContext *tc,
const StaticInstPtr staticInst,
TheISA::PCState pc,
const StaticInstPtr macroStaticInst = NULL);
protected:
typedef std::unique_ptr<Printable> PEntryPtr;
typedef TarmacTracerRecord::InstPtr InstPtr;
typedef TarmacTracerRecord::MemPtr MemPtr;
typedef TarmacTracerRecord::RegPtr RegPtr;
/**
* startTick and endTick allow to trace a specific window of ticks
* rather than the entire CPU execution.
*/
Tick startTick;
Tick endTick;
/**
* Collection of heterogeneous printable entries: could be
* representing either instructions, register or memory entries.
* When dealing with MacroInstructions the following separate queues
* will be used. micro-instruction entries will be buffered and
* dumped to the tracefile only at the end of the Macro.
*/
std::vector<InstPtr> instQueue;
std::vector<MemPtr> memQueue;
std::vector<RegPtr> regQueue;
};
} // namespace Trace
#endif // __ARCH_ARM_TRACERS_TARMAC_TRACER_HH__