Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / stracer.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: stracer.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21////////////////////////////////////////////////////////////
22//
23// File: stracer.cc
24//
25// Copyright (C) 2005-2007 Sun Microsystems, Inc.
26// All rights reserved.
27//
28
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <ctype.h>
33#include "types.h"
34#include "cpu_interface.h"
35#include "symbols.h"
36#include "stracer.h"
37#include "ui.h"
38#include "ui_elfsym.h"
39
40// set to 1 to debug this module
41#define DEBUG_ON 0
42
43
44//////////////////////////////////////////
45char *modes[] = { "u", "p", "h" };
46typedef enum { MODE_USER, MODE_PRIV, MODE_HVISOR} prmode_t;
47
48
49
50// list of open debug tracers
51static STracerContainer g_stracer_list;
52
53
54////////////////////////////////////////////////////////////
55//
56// each debug tracer is associated with output stream;
57// tracers could shared to output trace to the same stream;
58//
59
60static char console[] = "console";
61
62STracer * STracerContainer::alloc(const char *fname,SymTable *symtable)
63{
64 STracer *s = head;
65
66 if (fname == NULL)
67 fname = console;
68
69 // check if tracer is opened already
70 while (s)
71 {
72 if (strcmp(s->trace_name, fname)==0)
73 break;
74 else
75 s = s->next;
76 }
77
78 if (!s)
79 {
80 // add a new stream
81 s = new STracer(fname,symtable);
82 s->next = head;
83 head = s;
84 }
85 s->ref++; // update ref counter
86
87 return s;
88}
89
90int STracerContainer::dealloc (STracer *t)
91{
92 STracer *s = head;
93 STracer *prev = NULL;
94
95 // find it on the list
96 while (s)
97 {
98 if (t==s)
99 {
100 // update ref counter
101 if (--s->ref > 0)
102 return 1;
103
104 // remove it from the list
105 if (s == head)
106 head = s->next;
107 else
108 prev->next = s->next;
109
110 delete s;
111 return 1;
112 }
113 else
114 {
115 prev = s;
116 s = s->next;
117 }
118 }
119
120 return 0;
121}
122
123int STracerContainer::display(FILE *out)
124{
125 int ok = 0;
126 STracer *s = head;
127
128 while (s)
129 {
130 fprintf (out,"trace to %s\n", s->trace_name );
131 ok = 1;
132 s = s->next;
133 }
134 fprintf (out,"\n" );
135 return ok;
136}
137
138bool STracerContainer::is_found(STracer *t)
139{
140 STracer *s = head;
141
142 while (s)
143 {
144 if(s==t)
145 return true;
146 s = s->next;
147 }
148
149 return false;
150}
151
152
153
154///////////////////////////////////////////////////////////////////////
155//
156// debug tracer constructor
157//
158
159STracer::STracer (const char *fname, SymTable *symtable)
160{
161 sym_table = symtable;
162
163 // open a stream
164 if (fname && fname != console)
165 trace_name = strdup(fname);
166 else
167 trace_name = console;
168
169 if ( trace_name == console )
170 {
171 stream = ui->get_output_file();
172 }
173 else
174 {
175 stream = fopen (trace_name, "w");
176 if ( stream == NULL )
177 {
178 ui->error("cannot open %s, trace to output\n", trace_name);
179 trace_name = console;
180 stream = ui->get_output_file();
181 }
182 }
183
184 // set the stream to be unbuffered;
185 // tracing will b slower but we don't lose trace data
186 // in case of crash
187 setbuf(stream, NULL);
188
189 next = NULL;
190 ref = 0;
191}
192
193STracer::~STracer ()
194{
195 if (stream != ui->get_output_file())
196 fclose(stream);
197
198 if (trace_name != console)
199 free(trace_name);
200}
201
202
203int STracer::attach(VTracer_SAM_intf * /* intf */) { return 1; }
204
205
206
207
208
209
210///////////////////////////////////////////////////////////////
211//
212// print values from the trace record
213
214static int print_regs_update
215(
216 int cpuid,
217 int nregs, // total number of destination regs written
218 VCPU_RegType *dreg, // destination register type and index
219 uint64_t *dval, // destination reg value
220 FILE *stream // default is ui output
221)
222{
223 Vcpu* cpu = g_vcpu[cpuid];
224
225 for (int i=0; i<nregs; i++)
226 {
227 int rindex = dreg[i].r.id;
228 char reg_name[24];
229
230 const char format[] = "%i:\t%s=0x%llx\n";
231
232 switch(dreg[i].r.type)
233 {
234 case VCPU_PR_RTYPE:
235 fprintf (stream, format, cpuid, cpu->get_reg_name(VCPU_PR_0 + rindex), dval[i]);
236 break;
237
238 case VCPU_ASR_RTYPE:
239 fprintf (stream, format, cpuid, cpu->get_reg_name(VCPU_ASR_0 + rindex), dval[i]);
240 break;
241
242 case VCPU_INT_RTYPE:
243 fprintf (stream, format, cpuid, cpu->get_reg_name(VCPU_IRF_0 + rindex), dval[i]);
244 break;
245
246 case VCPU_FP_SINGLE_RTYPE:
247 fprintf (stream, format, cpuid, cpu->get_reg_name(VCPU_FRF_0 + rindex), dval[i]);
248 break;
249
250 case VCPU_FP_DOUBLE_RTYPE:
251 // @@ rindex is 0, 2, 4, .. , 62
252 fprintf (stream, format, cpuid, cpu->get_reg_name(VCPU_DRF_0 + rindex / 2), dval[i]);
253 break;
254
255 case VCPU_HPR_RTYPE:
256 fprintf (stream, format, cpuid, cpu->get_reg_name(VCPU_HPR_0 + rindex), dval[i]);
257 break;
258
259 default: // uknown type
260 continue;
261 }
262 }
263
264 return 0;
265}
266
267
268
269
270
271void print_value(uint64_t val, uint64_t mask, FILE *stream)
272{
273 for (int i=60; i>=0; i-=4)
274 {
275
276 if ((mask>>i) & 0xf)
277 {
278 uint8_t hb = uint8_t(val>>i)&0xf;
279 if(hb ==0) fprintf(stream, "0");
280 else fprintf(stream, "%1x", hb);
281 }
282 else
283 fprintf(stream, "-");
284 }
285}
286
287int STracer::instr ( VCPU_Instruction *i )
288{
289 // instruction line
290 const int LSIZE = 128;
291 char ibuf[LSIZE];
292 disassemble (i->opcode, i->pc_va, ibuf, LSIZE);
293
294
295 // check mode
296 prmode_t mode = MODE_USER;
297 if(i->hpstate & 4)
298 mode = MODE_HVISOR;
299 else if (i->pstate & 4)
300 mode = MODE_PRIV;
301
302 uint32_t context = i->pc_type==VCPU_VADDR ? i->icontext : Symbol::NO_CONTEXT;
303
304 // id, mode
305 int id = get_vcpu(i->cpuid)->id();
306 fprintf(stream,"%i: ", id);
307
308 // symname, va
309 if (sym_table) sym_table->fputs(i->pc_va, context, stream);
310 fprintf(stream,"%llx", i->pc_va);
311
312 // context
313 if (i->pc_type==VCPU_VADDR) fprintf(stream,"(%x)", i->icontext);
314
315 // pa, opcode, instr disassem, branch taken flag
316 fprintf(stream," : %llx [%08x] %s %s %s\n",
317 i->pc_pa, i->opcode, modes[mode], ibuf, i->taken? "(taken)":"");
318
319 // destination regs
320 if(i->nregs > 0)
321 print_regs_update (id, i->nregs, i->dreg, i->dval, stream );
322
323 if (i->st_num > 0)
324 {
325 fprintf(stream,"%i:\tstore ", id);
326 for(int ii=0; ii<i->st_num; ii++)
327 {
328 //print_value(i->st_mem_value[ii],i->st_bitmask, stream);
329 fprintf(stream, "%llx(%llx)", i->st_mem_value[ii], i->st_bitmask);
330 }
331
332 if (i->ea_type == VCPU_VADDR) // trace context
333 {
334 fprintf(stream," to %llx(%x):%llx ", i->ea_va, i->dcontext, i->ea_pa);
335 context = i->dcontext;
336 }
337 else
338 {
339 fprintf(stream," to %llx:%llx ", i->ea_va, i->ea_pa);
340 context = Symbol::NO_CONTEXT;
341 }
342
343 if (sym_table) sym_table->fputs(i->ea_va, context, stream);
344 fprintf(stream,"\n");
345 }
346 if (i->ld_num > 0)
347 {
348 fprintf(stream,"%i:\tload ", id);
349 for(int ii=0; ii<i->ld_num; ii++)
350 {
351 //print_value(i->ld_mem_value[ii],i->ld_bitmask, stream);
352 fprintf(stream," %llx(%llx)", i->ld_mem_value[ii], i->ld_bitmask);
353 }
354
355 if (i->ea_type == VCPU_VADDR) // trace context
356 {
357 fprintf(stream," from %llx(%x):%llx ", i->ea_va, i->dcontext, i->ea_pa);
358 context = i->dcontext;
359 }
360 else
361 {
362 fprintf(stream," from %llx:%llx ", i->ea_va, i->ea_pa);
363 context = Symbol::NO_CONTEXT;
364 }
365
366 if (sym_table) sym_table->fputs(i->ea_va, context, stream);
367 fprintf(stream,"\n");
368 }
369
370 return 0;
371}
372
373int STracer::trap ( VCPU_Trap *t )
374{
375 int id = get_vcpu(t->cpuid)->id();
376
377 fprintf(stream,"%i: TRAP 0x%x @pc=0x%llx\n", id, t->tno, t->pc_va);
378 print_regs_update (id, t->nregs, t->dreg, t->dval, stream );
379 return 0;
380}
381
382int STracer::tlb ( VCPU_TLB *s )
383{
384 int id = get_vcpu(s->cpuid)->id();
385
386 fprintf(stream,"%i: %s%d n:%d 0x%llx:0x%llx %s ", id,
387 s->tlb_type==0 ? "ITLB":(s->tlb_type==1 ?"DTLB":"TLB"),
388 s->tlb_no, s->tlb_index,
389 s->tte_tag, s->tte_data,
390 s->demap?"removed ":"inserted");
391
392 if (s->v()) fprintf(stream, "V ");
393 if (s->nfo()) fprintf(stream, "NFO ");
394 if (s->is_real) fprintf(stream, "R ");
395 if (s->ie()) fprintf(stream, "IE ");
396 if (s->e()) fprintf(stream, "E ");
397 if (s->cp()) fprintf(stream,"CP ");
398 if (s->cv()) fprintf(stream,"CV ");
399 if (s->p()) fprintf(stream, "P ");
400 if (s->ep()) fprintf(stream, "EP ");
401 if (s->w()) fprintf(stream, "W ");
402 if (s->l()) fprintf(stream, "L ");
403 if (s->g()) fprintf(stream, "G ");
404
405 uint64_t actual_page_size = (1ull << (13 + 3 * s->tte_page_size));
406 if (actual_page_size >> 30) {
407 fprintf(stream, ": %lldG, ", (actual_page_size>>30));
408 } else if (actual_page_size >> 20) {
409 fprintf(stream, ": %lldM, ", (actual_page_size >> 20));
410 } else {
411 fprintf(stream, ": %lldK, ", (actual_page_size >> 10));
412 }
413
414 fprintf(stream, "ctx 0x%x", s->tte_context);
415
416 if (s->format) { // sun4v
417 fprintf(stream, " partid 0x%x\n", s->partid);
418 } else {
419 fprintf(stream, "\n");
420 }
421
422 return 0;
423
424}
425
426
427int STracer::hwop ( VCPU_HwOp *s )
428{
429 int id = get_vcpu(s->cpuid)->id();
430 fprintf(stream,"%i: hwtw load %s tte tag=0x%llx data=0x%llx from tsb_addr=0x%llx\n",
431 id, s->op_type==0 ? "Instr":"Data", s->data[0], s->data[1], s->addr);
432
433 return 0;
434
435}
436
437
438
439int STracer::put_string(int cpuid, const char * str)
440{
441 fprintf(stream,"%s\n", str);
442 return 0;
443}
444
445
446
447
448///////////////////////////////////////////////////////
449//
450// set debug tracer on/off
451//
452int tracer_cmd
453(
454 trace_cmd_t cmd, // on/off/show status
455 int *trace_flag, // equal 1 to signal dtracer turn on/off, NULL - all vcpu's
456 const char *fname, // trace file name, if NULL - ui output
457 bool separate // if true, trace each vcpu to separate file/stream
458)
459{
460 if (cmd == STRACER_STATUS )
461 {
462
463 bool newline = true;
464 STracer *prev = NULL;
465 for (int i=0; i<=g_vcpu_id_max; i++)
466 {
467 Vcpu *vcpu = get_vcpu(i);
468 if (vcpu == NULL)
469 continue;
470
471 STracer *s = (STracer *)(vcpu->sys_intf.vtrace);
472 if (g_stracer_list.is_found(s))
473 {
474 if (s != prev )
475 newline = true;
476
477 if (newline)
478 {
479 printf("\ncollect trace to %s for cpu :", s->get_trace_name());
480 newline = false;
481 prev = s;
482 }
483 printf (" %i", i);
484 }
485 }
486
487 if (!prev)
488 ui->output("debug tracer is off\n\n");
489 else
490 {
491 #if(DEBUG_ON==1)
492 ui->verbose("\n\n");
493 g_stracer_list.display(ui->get_output_file());
494 #endif
495 ui->verbose("\n");
496 }
497
498 return 1;
499 }
500
501
502 if( cmd == STRACER_OFF ) // turn it off
503 {
504 for (int i=0; i<=g_vcpu_id_max; i++)
505 {
506 Vcpu *vcpu = get_vcpu(i);
507 if (vcpu == NULL)
508 continue;
509
510 STracer *s = (STracer *)vcpu->sys_intf.vtrace;
511 if ( s && (trace_flag == NULL || trace_flag[i] == 1) )
512 {
513 if (g_stracer_list.dealloc(s))
514 {
515 vcpu->sys_intf.vtrace = NULL;
516 vcpu->config.trace_on = 0;
517 ui->output("debug tracer is off for cpu %i\n", vcpu->id());
518 }
519 else
520 {
521 ui->error("cannot delete debug tracer for cpu %i\n,if you hooked up another analyzer - try to unload it first\n",
522 vcpu->id() );
523 return 0;
524 }
525 }
526 }
527 }
528 else if (cmd == STRACER_ON) // turn it on
529 {
530 if (fname == NULL && separate)
531 {
532 ui->error("cannot trace to console cpu running on separate worker threads\n");
533 return 0;
534 }
535 else if ( separate )
536 {
537 ui->output("collect trace for each cpu to separate files\n");
538 }
539
540
541 for (int i=0; i<=g_vcpu_id_max; i++)
542 {
543 Vcpu *vcpu = get_vcpu(i);
544 if (vcpu == NULL)
545 continue;
546
547 if ( trace_flag == NULL || trace_flag[i] == 1 )
548 {
549 if (vcpu->sys_intf.vtrace != NULL)
550 {
551 ui->error("another tracer for cpu %i is already on, need to turn it off to hook up debug tracer\n",
552 vcpu->id());
553 }
554 else
555 {
556 char trace_name[256];
557 if (separate)
558 {
559 sprintf(trace_name, "%s.cpu%i", fname, vcpu->id());
560 }
561
562
563 vcpu->sys_intf.vtrace = g_stracer_list.alloc(separate? trace_name:fname, g_sym_table);
564 vcpu->config.trace_on = 1;
565 ui->output("debug tracer is turned on for cpu %i\n", vcpu->id());
566 }
567 }
568 }
569
570 }
571 return 1;
572
573}