1/* 2 * Copyright (c) 2014 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Ali Saidi 38 */ 39 40#include "cpu/inst_pb_trace.hh" 41 42#include "base/callback.hh" 43#include "base/output.hh" 44#include "config/the_isa.hh" 45#include "cpu/static_inst.hh" 46#include "cpu/thread_context.hh" 47#include "debug/ExecEnable.hh" 48#include "params/InstPBTrace.hh" 49#include "proto/inst.pb.h" 50#include "sim/core.hh" 51 52namespace Trace { 53 54ProtoOutputStream *InstPBTrace::traceStream; 55 56void 57InstPBTraceRecord::dump() 58{ 59 // We're trying to build an instruction trace so we just want macro-ops and 60 // instructions that aren't macro-oped 61 if ((macroStaticInst && staticInst->isFirstMicroop()) || 62 !staticInst->isMicroop()) { 63 tracer.traceInst(thread, staticInst, pc); 64 } 65 66 // If this instruction accessed memory lets record it 67 if (getMemValid()) 68 tracer.traceMem(staticInst, getAddr(), getSize(), getFlags()); 69} 70 71InstPBTrace::InstPBTrace(const InstPBTraceParams *p) 72 : InstTracer(p), buf(nullptr), bufSize(0), curMsg(nullptr) 73{ 74 // Create our output file 75 createTraceFile(p->file_name); 76} 77 78void 79InstPBTrace::createTraceFile(std::string filename) 80{ 81 // Since there is only one output file for all tracers check if it exists 82 if (traceStream) 83 return; 84 85 traceStream = new ProtoOutputStream(simout.resolve(filename)); 86 87 // Output the header 88 ProtoMessage::InstHeader header_msg; 89 header_msg.set_obj_id("gem5 generated instruction trace"); 90 header_msg.set_ver(0); 91 header_msg.set_tick_freq(SimClock::Frequency); 92 header_msg.set_has_mem(true); 93 traceStream->write(header_msg); 94 95 // get a callback when we exit so we can close the file 96 Callback *cb = new MakeCallback<InstPBTrace, 97 &InstPBTrace::closeStreams>(this); 98 registerExitCallback(cb); 99} 100 101void 102InstPBTrace::closeStreams() 103{ 104 if (curMsg) { 105 traceStream->write(*curMsg); 106 delete curMsg; 107 curMsg = NULL; 108 } 109 110 if (!traceStream) 111 return; 112 113 delete traceStream; 114 traceStream = NULL; 115} 116 117InstPBTrace::~InstPBTrace() 118{ 119 closeStreams(); 120} 121 122InstPBTraceRecord* 123InstPBTrace::getInstRecord(Tick when, ThreadContext *tc, const StaticInstPtr si, 124 TheISA::PCState pc, const StaticInstPtr mi) 125{ 126 // Only record the trace if Exec debugging is enabled 127 if (!Debug::ExecEnable) 128 return NULL; 129 130 return new InstPBTraceRecord(*this, when, tc, si, pc, mi); 131 132} 133 134void 135InstPBTrace::traceInst(ThreadContext *tc, StaticInstPtr si, TheISA::PCState pc) 136{ 137 if (curMsg) { 138 /// @todo if we are running multi-threaded I assume we'd need a lock here 139 traceStream->write(*curMsg); 140 delete curMsg; 141 curMsg = NULL; 142 } 143 144 size_t instSize = si->asBytes(buf.get(), bufSize); 145 if (instSize > bufSize) { 146 bufSize = instSize; 147 buf.reset(new uint8_t[bufSize]); 148 instSize = si->asBytes(buf.get(), bufSize); 149 } 150 151 // Create a new instruction message and fill out the fields 152 curMsg = new ProtoMessage::Inst; 153 curMsg->set_pc(pc.pc()); 154 if (instSize == sizeof(uint32_t)) { 155 curMsg->set_inst(letoh(*reinterpret_cast<uint32_t *>(buf.get()))); 156 } else if (instSize) { 157 curMsg->set_inst_bytes( 158 std::string(reinterpret_cast<const char *>(buf.get()), bufSize)); 159 } 160 curMsg->set_cpuid(tc->cpuId()); 161 curMsg->set_tick(curTick()); 162 curMsg->set_type(static_cast<ProtoMessage::Inst_InstType>(si->opClass())); 163} 164 165void 166InstPBTrace::traceMem(StaticInstPtr si, Addr a, Addr s, unsigned f) 167{ 168 panic_if(!curMsg, "Memory access w/o msg?!"); 169 170 // We do a poor job identifying macro-ops that are load/stores 171 curMsg->set_type(static_cast<ProtoMessage::Inst_InstType>(si->opClass())); 172 173 ProtoMessage::Inst::MemAccess *mem_msg = curMsg->add_mem_access(); 174 mem_msg->set_addr(a); 175 mem_msg->set_size(s); 176 mem_msg->set_mem_flags(f); 177 178} 179 180} // namespace Trace 181 182 183Trace::InstPBTrace* 184InstPBTraceParams::create() 185{ 186 return new Trace::InstPBTrace(this); 187} 188 189