exetrace.cc revision 3588:e4ce301f8c7d
1/* 2 * Copyright (c) 2001-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Lisa Hsu 30 * Nathan Binkert 31 * Steve Raasch 32 */ 33 34#include <fstream> 35#include <iomanip> 36#include <sys/ipc.h> 37#include <sys/shm.h> 38 39#include "arch/regfile.hh" 40#include "arch/utility.hh" 41#include "base/loader/symtab.hh" 42#include "cpu/base.hh" 43#include "cpu/exetrace.hh" 44#include "cpu/static_inst.hh" 45#include "sim/param.hh" 46#include "sim/system.hh" 47 48//XXX This is temporary 49#include "arch/isa_specific.hh" 50#include "cpu/m5legion_interface.h" 51 52using namespace std; 53using namespace TheISA; 54 55namespace Trace { 56SharedData *shared_data = NULL; 57} 58 59//////////////////////////////////////////////////////////////////////// 60// 61// Methods for the InstRecord object 62// 63 64 65void 66Trace::InstRecord::dump(ostream &outs) 67{ 68 if (flags[PRINT_REG_DELTA]) 69 { 70#if THE_ISA == SPARC_ISA 71 //Don't print what happens for each micro-op, just print out 72 //once at the last op, and for regular instructions. 73 if(!staticInst->isMicroOp() || staticInst->isLastMicroOp()) 74 { 75 static uint64_t regs[32] = { 76 0, 0, 0, 0, 0, 0, 0, 0, 77 0, 0, 0, 0, 0, 0, 0, 0, 78 0, 0, 0, 0, 0, 0, 0, 0, 79 0, 0, 0, 0, 0, 0, 0, 0}; 80 static uint64_t ccr = 0; 81 static uint64_t y = 0; 82 static uint64_t floats[32]; 83 uint64_t newVal; 84 static const char * prefixes[4] = {"G", "O", "L", "I"}; 85 86 outs << hex; 87 outs << "PC = " << thread->readNextPC(); 88 outs << " NPC = " << thread->readNextNPC(); 89 newVal = thread->readMiscReg(SparcISA::MISCREG_CCR); 90 if(newVal != ccr) 91 { 92 outs << " CCR = " << newVal; 93 ccr = newVal; 94 } 95 newVal = thread->readMiscReg(SparcISA::MISCREG_Y); 96 if(newVal != y) 97 { 98 outs << " Y = " << newVal; 99 y = newVal; 100 } 101 for(int y = 0; y < 4; y++) 102 { 103 for(int x = 0; x < 8; x++) 104 { 105 int index = x + 8 * y; 106 newVal = thread->readIntReg(index); 107 if(regs[index] != newVal) 108 { 109 outs << " " << prefixes[y] << dec << x << " = " << hex << newVal; 110 regs[index] = newVal; 111 } 112 } 113 } 114 for(int y = 0; y < 32; y++) 115 { 116 newVal = thread->readFloatRegBits(2 * y, 64); 117 if(floats[y] != newVal) 118 { 119 outs << " F" << dec << (2 * y) << " = " << hex << newVal; 120 floats[y] = newVal; 121 } 122 } 123 outs << dec << endl; 124 } 125#endif 126 } 127 else if (flags[INTEL_FORMAT]) { 128#if FULL_SYSTEM 129 bool is_trace_system = (thread->getCpuPtr()->system->name() == trace_system); 130#else 131 bool is_trace_system = true; 132#endif 133 if (is_trace_system) { 134 ccprintf(outs, "%7d ) ", cycle); 135 outs << "0x" << hex << PC << ":\t"; 136 if (staticInst->isLoad()) { 137 outs << "<RD 0x" << hex << addr; 138 outs << ">"; 139 } else if (staticInst->isStore()) { 140 outs << "<WR 0x" << hex << addr; 141 outs << ">"; 142 } 143 outs << endl; 144 } 145 } else { 146 if (flags[PRINT_CYCLE]) 147 ccprintf(outs, "%7d: ", cycle); 148 149 outs << thread->getCpuPtr()->name() << " "; 150 151 if (flags[TRACE_MISSPEC]) 152 outs << (misspeculating ? "-" : "+") << " "; 153 154 if (flags[PRINT_THREAD_NUM]) 155 outs << "T" << thread->getThreadNum() << " : "; 156 157 158 std::string sym_str; 159 Addr sym_addr; 160 if (debugSymbolTable 161 && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) 162 && flags[PC_SYMBOL]) { 163 if (PC != sym_addr) 164 sym_str += csprintf("+%d", PC - sym_addr); 165 outs << "@" << sym_str << " : "; 166 } 167 else { 168 outs << "0x" << hex << PC << " : "; 169 } 170 171 // 172 // Print decoded instruction 173 // 174 175#if defined(__GNUC__) && (__GNUC__ < 3) 176 // There's a bug in gcc 2.x library that prevents setw() 177 // from working properly on strings 178 string mc(staticInst->disassemble(PC, debugSymbolTable)); 179 while (mc.length() < 26) 180 mc += " "; 181 outs << mc; 182#else 183 outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); 184#endif 185 186 outs << " : "; 187 188 if (flags[PRINT_OP_CLASS]) { 189 outs << opClassStrings[staticInst->opClass()] << " : "; 190 } 191 192 if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) { 193 outs << " D="; 194#if 0 195 if (data_status == DataDouble) 196 ccprintf(outs, "%f", data.as_double); 197 else 198 ccprintf(outs, "%#018x", data.as_int); 199#else 200 ccprintf(outs, "%#018x", data.as_int); 201#endif 202 } 203 204 if (flags[PRINT_EFF_ADDR] && addr_valid) 205 outs << " A=0x" << hex << addr; 206 207 if (flags[PRINT_INT_REGS] && regs_valid) { 208 for (int i = 0; i < TheISA::NumIntRegs;) 209 for (int j = i + 1; i <= j; i++) 210 ccprintf(outs, "r%02d = %#018x%s", i, 211 iregs->regs.readReg(i), 212 ((i == j) ? "\n" : " ")); 213 outs << "\n"; 214 } 215 216 if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid) 217 outs << " FetchSeq=" << dec << fetch_seq; 218 219 if (flags[PRINT_CP_SEQ] && cp_seq_valid) 220 outs << " CPSeq=" << dec << cp_seq; 221 222 // 223 // End of line... 224 // 225 outs << endl; 226 } 227#if THE_ISA == SPARC_ISA 228 // Compare 229 if (flags[LEGION_LOCKSTEP]) 230 { 231 bool compared = false; 232 bool diffPC = false; 233 bool diffInst = false; 234 bool diffRegs = false; 235 236 if(!staticInst->isMicroOp() || staticInst->isLastMicroOp()) { 237 while (!compared) { 238 if (shared_data->flags == OWN_M5) { 239 if (shared_data->pc != PC) 240 diffPC = true; 241 if (shared_data->instruction != staticInst->machInst) 242 diffInst = true; 243 for (int i = 0; i < TheISA::NumIntRegs; i++) { 244 if (thread->readIntReg(i) != shared_data->intregs[i]) 245 diffRegs = true; 246 } 247 248 if (diffPC || diffInst || diffRegs ) { 249 outs << "Differences found between M5 and Legion:"; 250 if (diffPC) 251 outs << " [PC]"; 252 if (diffInst) 253 outs << " [Instruction]"; 254 if (diffRegs) 255 outs << " [IntRegs]"; 256 outs << endl << endl;; 257 258 outs << setfill(' ') << setw(15) 259 << "M5 PC: " << "0x"<< setw(16) << setfill('0') 260 << hex << PC << endl; 261 outs << setfill(' ') << setw(15) 262 << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex 263 << shared_data->pc << endl << endl; 264 265 outs << setfill(' ') << setw(15) 266 << "M5 Inst: " << "0x"<< setw(8) 267 << setfill('0') << hex << staticInst->machInst 268 << staticInst->disassemble(PC, debugSymbolTable) 269 << endl; 270 271 StaticInstPtr legionInst = StaticInst::decode(makeExtMI(shared_data->instruction, thread)); 272 outs << setfill(' ') << setw(15) 273 << " Legion Inst: " 274 << "0x" << setw(8) << setfill('0') << hex 275 << shared_data->instruction 276 << legionInst->disassemble(shared_data->pc, debugSymbolTable) 277 << endl; 278 279 outs << endl; 280 281 static const char * regtypes[4] = {"%g", "%o", "%l", "%i"}; 282 for(int y = 0; y < 4; y++) 283 { 284 for(int x = 0; x < 8; x++) 285 { 286 outs << regtypes[y] << x << " " ; 287 outs << "0x" << hex << setw(16) << thread->readIntReg(y*8+x); 288 if (thread->readIntReg(y*8 + x) != shared_data->intregs[y*8+x]) 289 outs << " X "; 290 else 291 outs << " | "; 292 outs << "0x" << setw(16) << hex << shared_data->intregs[y*8+x] 293 << endl; 294 } 295 } 296 fatal("Differences found between Legion and M5\n"); 297 } 298 299 compared = true; 300 shared_data->flags = OWN_LEGION; 301 } 302 } // while 303 } // if not microop 304 } 305#endif 306} 307 308 309vector<bool> Trace::InstRecord::flags(NUM_BITS); 310string Trace::InstRecord::trace_system; 311 312//////////////////////////////////////////////////////////////////////// 313// 314// Parameter space for per-cycle execution address tracing options. 315// Derive from ParamContext so we can override checkParams() function. 316// 317class ExecutionTraceParamContext : public ParamContext 318{ 319 public: 320 ExecutionTraceParamContext(const string &_iniSection) 321 : ParamContext(_iniSection) 322 { 323 } 324 325 void checkParams(); // defined at bottom of file 326}; 327 328ExecutionTraceParamContext exeTraceParams("exetrace"); 329 330Param<bool> exe_trace_spec(&exeTraceParams, "speculative", 331 "capture speculative instructions", true); 332 333Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle", 334 "print cycle number", true); 335Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass", 336 "print op class", true); 337Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread", 338 "print thread number", true); 339Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr", 340 "print effective address", true); 341Param<bool> exe_trace_print_data(&exeTraceParams, "print_data", 342 "print result data", true); 343Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs", 344 "print all integer regs", false); 345Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq", 346 "print fetch sequence number", false); 347Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq", 348 "print correct-path sequence number", false); 349Param<bool> exe_trace_print_reg_delta(&exeTraceParams, "print_reg_delta", 350 "print which registers changed to what", false); 351Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol", 352 "Use symbols for the PC if available", true); 353Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format", 354 "print trace in intel compatible format", false); 355Param<bool> exe_trace_legion_lockstep(&exeTraceParams, "legion_lockstep", 356 "Compare sim state to legion state every cycle", 357 false); 358Param<string> exe_trace_system(&exeTraceParams, "trace_system", 359 "print trace of which system (client or server)", 360 "client"); 361 362 363// 364// Helper function for ExecutionTraceParamContext::checkParams() just 365// to get us into the InstRecord namespace 366// 367void 368Trace::InstRecord::setParams() 369{ 370 flags[TRACE_MISSPEC] = exe_trace_spec; 371 372 flags[PRINT_CYCLE] = exe_trace_print_cycle; 373 flags[PRINT_OP_CLASS] = exe_trace_print_opclass; 374 flags[PRINT_THREAD_NUM] = exe_trace_print_thread; 375 flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr; 376 flags[PRINT_EFF_ADDR] = exe_trace_print_data; 377 flags[PRINT_INT_REGS] = exe_trace_print_iregs; 378 flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq; 379 flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq; 380 flags[PRINT_REG_DELTA] = exe_trace_print_reg_delta; 381 flags[PC_SYMBOL] = exe_trace_pc_symbol; 382 flags[INTEL_FORMAT] = exe_trace_intel_format; 383 flags[LEGION_LOCKSTEP] = exe_trace_legion_lockstep; 384 trace_system = exe_trace_system; 385 386 // If were going to be in lockstep with Legion 387 // Setup shared memory, and get otherwise ready 388 if (flags[LEGION_LOCKSTEP]) { 389 int shmfd = shmget(getuid(), sizeof(SharedData), 0777); 390 if (shmfd < 0) 391 fatal("Couldn't get shared memory fd. Is Legion running?"); 392 393 shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND); 394 if (shared_data == (SharedData*)-1) 395 fatal("Couldn't allocate shared memory"); 396 397 if (shared_data->flags != OWN_M5) 398 fatal("Shared memory has invalid owner"); 399 400 if (shared_data->version != VERSION) 401 fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION, 402 shared_data->version); 403 404 } 405} 406 407void 408ExecutionTraceParamContext::checkParams() 409{ 410 Trace::InstRecord::setParams(); 411} 412 413