exetrace.cc revision 3603:714467743f9b
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 "arch/tlb.hh"
42#include "base/loader/symtab.hh"
43#include "cpu/base.hh"
44#include "cpu/exetrace.hh"
45#include "cpu/static_inst.hh"
46#include "sim/param.hh"
47#include "sim/system.hh"
48
49//XXX This is temporary
50#include "arch/isa_specific.hh"
51#include "cpu/m5legion_interface.h"
52
53using namespace std;
54using namespace TheISA;
55
56namespace Trace {
57SharedData *shared_data = NULL;
58}
59
60////////////////////////////////////////////////////////////////////////
61//
62//  Methods for the InstRecord object
63//
64
65
66void
67Trace::InstRecord::dump(ostream &outs)
68{
69    if (flags[PRINT_REG_DELTA])
70    {
71#if THE_ISA == SPARC_ISA
72        //Don't print what happens for each micro-op, just print out
73        //once at the last op, and for regular instructions.
74        if(!staticInst->isMicroOp() || staticInst->isLastMicroOp())
75        {
76            static uint64_t regs[32] = {
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                0, 0, 0, 0, 0, 0, 0, 0};
81            static uint64_t ccr = 0;
82            static uint64_t y = 0;
83            static uint64_t floats[32];
84            uint64_t newVal;
85            static const char * prefixes[4] = {"G", "O", "L", "I"};
86
87            outs << hex;
88            outs << "PC = " << thread->readNextPC();
89            outs << " NPC = " << thread->readNextNPC();
90            newVal = thread->readMiscReg(SparcISA::MISCREG_CCR);
91            if(newVal != ccr)
92            {
93                outs << " CCR = " << newVal;
94                ccr = newVal;
95            }
96            newVal = thread->readMiscReg(SparcISA::MISCREG_Y);
97            if(newVal != y)
98            {
99                outs << " Y = " << newVal;
100                y = newVal;
101            }
102            for(int y = 0; y < 4; y++)
103            {
104                for(int x = 0; x < 8; x++)
105                {
106                    int index = x + 8 * y;
107                    newVal = thread->readIntReg(index);
108                    if(regs[index] != newVal)
109                    {
110                        outs << " " << prefixes[y] << dec << x << " = " << hex << newVal;
111                        regs[index] = newVal;
112                    }
113                }
114            }
115            for(int y = 0; y < 32; y++)
116            {
117                newVal = thread->readFloatRegBits(2 * y, 64);
118                if(floats[y] != newVal)
119                {
120                    outs << " F" << dec << (2 * y) << " = " << hex << newVal;
121                    floats[y] = newVal;
122                }
123            }
124            outs << dec << endl;
125        }
126#endif
127    }
128    else if (flags[INTEL_FORMAT]) {
129#if FULL_SYSTEM
130        bool is_trace_system = (thread->getCpuPtr()->system->name() == trace_system);
131#else
132        bool is_trace_system = true;
133#endif
134        if (is_trace_system) {
135            ccprintf(outs, "%7d ) ", cycle);
136            outs << "0x" << hex << PC << ":\t";
137            if (staticInst->isLoad()) {
138                outs << "<RD 0x" << hex << addr;
139                outs << ">";
140            } else if (staticInst->isStore()) {
141                outs << "<WR 0x" << hex << addr;
142                outs << ">";
143            }
144            outs << endl;
145        }
146    } else {
147        if (flags[PRINT_CYCLE])
148            ccprintf(outs, "%7d: ", cycle);
149
150        outs << thread->getCpuPtr()->name() << " ";
151
152        if (flags[TRACE_MISSPEC])
153            outs << (misspeculating ? "-" : "+") << " ";
154
155        if (flags[PRINT_THREAD_NUM])
156            outs << "T" << thread->getThreadNum() << " : ";
157
158
159        std::string sym_str;
160        Addr sym_addr;
161        if (debugSymbolTable
162            && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)
163            && flags[PC_SYMBOL]) {
164            if (PC != sym_addr)
165                sym_str += csprintf("+%d", PC - sym_addr);
166            outs << "@" << sym_str << " : ";
167        }
168        else {
169            outs << "0x" << hex << PC << " : ";
170        }
171
172        //
173        //  Print decoded instruction
174        //
175
176#if defined(__GNUC__) && (__GNUC__ < 3)
177        // There's a bug in gcc 2.x library that prevents setw()
178        // from working properly on strings
179        string mc(staticInst->disassemble(PC, debugSymbolTable));
180        while (mc.length() < 26)
181            mc += " ";
182        outs << mc;
183#else
184        outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable);
185#endif
186
187        outs << " : ";
188
189        if (flags[PRINT_OP_CLASS]) {
190            outs << opClassStrings[staticInst->opClass()] << " : ";
191        }
192
193        if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) {
194            outs << " D=";
195#if 0
196            if (data_status == DataDouble)
197                ccprintf(outs, "%f", data.as_double);
198            else
199                ccprintf(outs, "%#018x", data.as_int);
200#else
201            ccprintf(outs, "%#018x", data.as_int);
202#endif
203        }
204
205        if (flags[PRINT_EFF_ADDR] && addr_valid)
206            outs << " A=0x" << hex << addr;
207
208        if (flags[PRINT_INT_REGS] && regs_valid) {
209            for (int i = 0; i < TheISA::NumIntRegs;)
210                for (int j = i + 1; i <= j; i++)
211                    ccprintf(outs, "r%02d = %#018x%s", i,
212                            iregs->regs.readReg(i),
213                            ((i == j) ? "\n" : "    "));
214            outs << "\n";
215        }
216
217        if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid)
218            outs << "  FetchSeq=" << dec << fetch_seq;
219
220        if (flags[PRINT_CP_SEQ] && cp_seq_valid)
221            outs << "  CPSeq=" << dec << cp_seq;
222
223        //
224        //  End of line...
225        //
226        outs << endl;
227    }
228#if THE_ISA == SPARC_ISA
229    // Compare
230    if (flags[LEGION_LOCKSTEP])
231    {
232        bool compared = false;
233        bool diffPC   = false;
234        bool diffInst = false;
235        bool diffRegs = false;
236        Addr m5Pc, lgnPc;
237
238
239        if(!staticInst->isMicroOp() || staticInst->isLastMicroOp()) {
240            while (!compared) {
241                m5Pc = PC & TheISA::PAddrImplMask;
242                lgnPc = shared_data->pc & TheISA::PAddrImplMask;
243                if (shared_data->flags == OWN_M5) {
244                    if (lgnPc != m5Pc)
245                       diffPC = true;
246                    if (shared_data->instruction != staticInst->machInst)
247                        diffInst = true;
248                    for (int i = 0; i < TheISA::NumRegularIntRegs; i++) {
249                        if (thread->readIntReg(i) != shared_data->intregs[i]) {
250                            diffRegs = true;
251                        }
252                    }
253
254                    if (diffPC || diffInst || diffRegs ) {
255                        outs << "Differences found between M5 and Legion:";
256                        if (diffPC)
257                            outs << " [PC]";
258                        if (diffInst)
259                            outs << " [Instruction]";
260                        if (diffRegs)
261                            outs << " [IntRegs]";
262                        outs << endl << endl;
263
264                        outs << right << setfill(' ') << setw(15)
265                             << "M5 PC: " << "0x"<< setw(16) << setfill('0')
266                             << hex << m5Pc << endl;
267                        outs << setfill(' ') << setw(15)
268                             << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex
269                             << lgnPc << endl << endl;
270
271                        outs << setfill(' ') << setw(15)
272                             << "M5 Inst: "  << "0x"<< setw(8)
273                             << setfill('0') << hex << staticInst->machInst
274                             << staticInst->disassemble(m5Pc, debugSymbolTable)
275                             << endl;
276
277                        StaticInstPtr legionInst = StaticInst::decode(makeExtMI(shared_data->instruction, thread));
278                        outs << setfill(' ') << setw(15)
279                             << " Legion Inst: "
280                             << "0x" << setw(8) << setfill('0') << hex
281                             << shared_data->instruction
282                             << legionInst->disassemble(lgnPc, debugSymbolTable)
283                             << endl;
284
285                        outs << endl;
286
287                        static const char * regtypes[4] = {"%g", "%o", "%l", "%i"};
288                        for(int y = 0; y < 4; y++)
289                        {
290                            for(int x = 0; x < 8; x++)
291                            {
292                                outs << regtypes[y] << x << "         " ;
293                                outs <<  "0x" << hex << setw(16) << thread->readIntReg(y*8+x);
294                                if (thread->readIntReg(y*8 + x) != shared_data->intregs[y*8+x])
295                                    outs << "     X     ";
296                                else
297                                    outs << "     |     ";
298                                outs << "0x" << setw(16) << hex << shared_data->intregs[y*8+x]
299                                     << endl;
300                            }
301                        }
302                        fatal("Differences found between Legion and M5\n");
303                    }
304
305                    compared = true;
306                    shared_data->flags = OWN_LEGION;
307                }
308            } // while
309        } // if not microop
310    }
311#endif
312}
313
314
315vector<bool> Trace::InstRecord::flags(NUM_BITS);
316string Trace::InstRecord::trace_system;
317
318////////////////////////////////////////////////////////////////////////
319//
320// Parameter space for per-cycle execution address tracing options.
321// Derive from ParamContext so we can override checkParams() function.
322//
323class ExecutionTraceParamContext : public ParamContext
324{
325  public:
326    ExecutionTraceParamContext(const string &_iniSection)
327        : ParamContext(_iniSection)
328        {
329        }
330
331    void checkParams();	// defined at bottom of file
332};
333
334ExecutionTraceParamContext exeTraceParams("exetrace");
335
336Param<bool> exe_trace_spec(&exeTraceParams, "speculative",
337                           "capture speculative instructions", true);
338
339Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle",
340                                  "print cycle number", true);
341Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass",
342                                  "print op class", true);
343Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread",
344                                  "print thread number", true);
345Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr",
346                                  "print effective address", true);
347Param<bool> exe_trace_print_data(&exeTraceParams, "print_data",
348                                  "print result data", true);
349Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs",
350                                  "print all integer regs", false);
351Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq",
352                                  "print fetch sequence number", false);
353Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq",
354                                  "print correct-path sequence number", false);
355Param<bool> exe_trace_print_reg_delta(&exeTraceParams, "print_reg_delta",
356                                  "print which registers changed to what", false);
357Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol",
358                                  "Use symbols for the PC if available", true);
359Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format",
360                                   "print trace in intel compatible format", false);
361Param<bool> exe_trace_legion_lockstep(&exeTraceParams, "legion_lockstep",
362                                   "Compare sim state to legion state every cycle",
363                                   false);
364Param<string> exe_trace_system(&exeTraceParams, "trace_system",
365                                   "print trace of which system (client or server)",
366                                   "client");
367
368
369//
370// Helper function for ExecutionTraceParamContext::checkParams() just
371// to get us into the InstRecord namespace
372//
373void
374Trace::InstRecord::setParams()
375{
376    flags[TRACE_MISSPEC]     = exe_trace_spec;
377
378    flags[PRINT_CYCLE]       = exe_trace_print_cycle;
379    flags[PRINT_OP_CLASS]    = exe_trace_print_opclass;
380    flags[PRINT_THREAD_NUM]  = exe_trace_print_thread;
381    flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr;
382    flags[PRINT_EFF_ADDR]    = exe_trace_print_data;
383    flags[PRINT_INT_REGS]    = exe_trace_print_iregs;
384    flags[PRINT_FETCH_SEQ]   = exe_trace_print_fetchseq;
385    flags[PRINT_CP_SEQ]      = exe_trace_print_cp_seq;
386    flags[PRINT_REG_DELTA]   = exe_trace_print_reg_delta;
387    flags[PC_SYMBOL]         = exe_trace_pc_symbol;
388    flags[INTEL_FORMAT]      = exe_trace_intel_format;
389    flags[LEGION_LOCKSTEP]   = exe_trace_legion_lockstep;
390    trace_system	     = exe_trace_system;
391
392    // If were going to be in lockstep with Legion
393    // Setup shared memory, and get otherwise ready
394    if (flags[LEGION_LOCKSTEP]) {
395        int shmfd = shmget('M' << 24 | getuid(), sizeof(SharedData), 0777);
396        if (shmfd < 0)
397            fatal("Couldn't get shared memory fd. Is Legion running?");
398
399        shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND);
400        if (shared_data == (SharedData*)-1)
401            fatal("Couldn't allocate shared memory");
402
403        if (shared_data->flags != OWN_M5)
404            fatal("Shared memory has invalid owner");
405
406        if (shared_data->version != VERSION)
407            fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION,
408                    shared_data->version);
409
410        // step legion forward one cycle so we can get register values
411        shared_data->flags = OWN_LEGION;
412    }
413}
414
415void
416ExecutionTraceParamContext::checkParams()
417{
418    Trace::InstRecord::setParams();
419}
420
421