Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: trace.c | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | /* | |
24 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
25 | * Use is subject to license terms. | |
26 | */ | |
27 | #pragma ident "@(#)trace.c 1.8 07/01/09 SMI" | |
28 | ||
29 | #include <stdio.h> | |
30 | #include <stdlib.h> | |
31 | #include <unistd.h> | |
32 | #include <sys/types.h> | |
33 | #include <sys/ipc.h> | |
34 | #include <sys/shm.h> | |
35 | #include <assert.h> | |
36 | #include <string.h> | |
37 | ||
38 | #include "ss_common.h" | |
39 | #include "niagara.h" | |
40 | ||
41 | #if 1 | |
42 | #define DBGP(s) do { s } while (0) | |
43 | #endif | |
44 | ||
45 | void dbg_trace(simcpu_t *sp, uint32_t rawi); | |
46 | void dbg_trace_parse(void); | |
47 | void dbg_trace_dump(void); | |
48 | ||
49 | static void dump_intregs(uint64_t *data); | |
50 | ||
51 | /* | |
52 | * Trace modes | |
53 | * ALL = trace all instns for all values of %pc | |
54 | * PC = start trace when "start" %pc is encountered | |
55 | * stop when 'end' %pc is encountered. | |
56 | * INSTN = only trace when instn count is within start-end range | |
57 | */ | |
58 | enum trace_modes { ALL, PC, INSTN }; | |
59 | ||
60 | /* start/end for pc,instn tracing */ | |
61 | uint32_t trace_mode; | |
62 | char trace_mode_str[64]; | |
63 | uint64_t start_trace = 0x0; | |
64 | uint64_t end_trace = 0x0; | |
65 | bool_t dump_regs = false; | |
66 | ||
67 | /* | |
68 | * This will be called while parsing the conf file | |
69 | * to allow this hook to parse specific options from | |
70 | * the conf file. | |
71 | * | |
72 | * Format of trace directive is: | |
73 | * debug_hook [trace] [mode] [regs] [start] [end]; | |
74 | * | |
75 | * [trace] - we've already parsed this. That's how we got here. | |
76 | * [mode] - is one of [all, pc, instn] | |
77 | * all : traces all instns (no start, end values) | |
78 | * pc : just trace when %pc is withing start-end range | |
79 | * instn : just trace when instn count is within start-end | |
80 | * [regs] - if defined, we dump the %g,%o,%l,%i regs with each sample. | |
81 | * [start] | |
82 | * [end] - only trace when %pc or inst_cnt is within [start]-[end] | |
83 | * range | |
84 | * | |
85 | * examples: | |
86 | * trace all; | |
87 | * trace all regs; | |
88 | * trace pc 0x123 0x456; | |
89 | * trace pc regs 0x123 0x456; | |
90 | * trace instn 0x123 0x456; | |
91 | * trace instn regs 0x123 0x456; | |
92 | */ | |
93 | void | |
94 | dbg_trace_parse(void) | |
95 | { | |
96 | lexer_tok_t tok; | |
97 | ||
98 | DBGP(printf("\nInside dbg_trace_parse()");); | |
99 | ||
100 | tok = lex_get_token(); /* trace mode */ | |
101 | strcpy(trace_mode_str, lex.strp); | |
102 | ||
103 | if (streq(lex.strp, "all")) | |
104 | trace_mode = ALL; | |
105 | else if (streq(lex.strp, "pc")) | |
106 | trace_mode = PC; | |
107 | else if (streq(lex.strp, "instn")) | |
108 | trace_mode = INSTN; | |
109 | else | |
110 | lex_fatal("unknown trace_mode [%s] parsing config", lex.strp); | |
111 | ||
112 | /* parse optional regs token */ | |
113 | tok = lex_get_token(); | |
114 | if (streq(lex.strp, "regs")) { | |
115 | dump_regs = true; | |
116 | } else { | |
117 | lex_unget(); /* no regs option, continue */ | |
118 | } | |
119 | ||
120 | /* | |
121 | * continue parsing conf file | |
122 | */ | |
123 | switch (trace_mode) { | |
124 | case ALL: | |
125 | break; /* no more parsing for 'all' mode */ | |
126 | case PC: | |
127 | case INSTN: | |
128 | lex_get(T_Number); /* start pc/instn */ | |
129 | start_trace = lex.val; | |
130 | lex_get(T_Number); /* end pc/instn */ | |
131 | end_trace = lex.val; | |
132 | break; | |
133 | } | |
134 | ||
135 | DBGP(printf("\ndbg_trace_parse: mode=%s, start=0x%llx, end=0x%llx", | |
136 | trace_mode_str, start_trace, end_trace);); | |
137 | ||
138 | /* | |
139 | * return to parse_debug_hook() which will take care | |
140 | * of parsing the last semi colon. | |
141 | */ | |
142 | } | |
143 | ||
144 | /* | |
145 | * This function will get called before each instruction | |
146 | * gets executed. For performance reasons, we may want to | |
147 | * store the data in a buffer and post-process it later. | |
148 | */ | |
149 | void | |
150 | dbg_trace(simcpu_t *sp, uint32_t rawi) | |
151 | { | |
152 | sparcv9_cpu_t *v9p; | |
153 | char trace_buf[64]; | |
154 | static bool_t first_time = true; | |
155 | ||
156 | /* | |
157 | * If a trace range is given, we only trace within that | |
158 | * range | |
159 | */ | |
160 | switch (trace_mode) { | |
161 | case ALL: | |
162 | break; /* trace everything */ | |
163 | case PC: | |
164 | if ((sp->pc < start_trace) || (sp->pc > end_trace)) { | |
165 | return; /* only trace when %pc is in range */ | |
166 | } | |
167 | break; | |
168 | case INSTN: | |
169 | if ((sp->cycle < start_trace) || | |
170 | (sp->cycle > end_trace)) { | |
171 | return; /* only trace when instn count is in range */ | |
172 | } | |
173 | break; | |
174 | } | |
175 | ||
176 | v9p = (sparcv9_cpu_t *)sp->specificp; | |
177 | sparcv9_idis(trace_buf, sizeof (trace_buf), | |
178 | FE_INSTN(rawi), sp->pc); | |
179 | ||
180 | if (first_time) { | |
181 | printf("\n[cpu] Instn_# tl:tt/gl state %%pc [raw_instn]" | |
182 | "\tinstn\n"); | |
183 | first_time = false; | |
184 | } | |
185 | ||
186 | /* | |
187 | * When printing registers, we print them in their state prior to | |
188 | * executing the instruction in question. | |
189 | */ | |
190 | if (dump_regs) | |
191 | dump_intregs(sp->intreg); | |
192 | ||
193 | printf("\n[0x%llx] 0x%llx %x:%x/%x 0x%x 0x%llx [0x%08x]\t%s", | |
194 | sp->gid, sp->cycle, | |
195 | v9p->tl, | |
196 | (v9p->tl == 0) ? 0 : N_TT(v9p, v9p->tl), | |
197 | v9p->gl, | |
198 | v9p->state, | |
199 | sp->pc, | |
200 | FE_INSTN(rawi), | |
201 | trace_buf); | |
202 | } | |
203 | ||
204 | static void | |
205 | dump_intregs(uint64_t *intreg) | |
206 | { | |
207 | int i; | |
208 | ||
209 | for (i = 0; i < 8; i++) { | |
210 | printf("\ng%d=0x%016llx o%d=0x%016llx l%d=0x%016llx i%d=0x%016llx", | |
211 | i, intreg[i], | |
212 | i, intreg[i+8], | |
213 | i, intreg[i+16], | |
214 | i, intreg[i+24]); | |
215 | } | |
216 | } | |
217 | ||
218 | void | |
219 | dbg_trace_dump(void) | |
220 | { | |
221 | printf("\ndbg_trace_dump: caled with mode=%s, start=0x%llx, "\ | |
222 | "end=0x%llx\n", trace_mode_str, start_trace, end_trace); | |
223 | } |