Commit | Line | Data |
---|---|---|
e9b2f579 DE |
1 | /* Simulator tracing/debugging support. |
2 | Copyright (C) 1997 Free Software Foundation, Inc. | |
3 | Contributed by Cygnus Support. | |
4 | ||
5 | This file is part of GDB, the GNU debugger. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License along | |
18 | with this program; if not, write to the Free Software Foundation, Inc., | |
19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
20 | ||
21 | #include "sim-main.h" | |
22 | #include "sim-io.h" | |
3971886a | 23 | #include "sim-options.h" |
a7724171 | 24 | #include "bfd.h" |
e9b2f579 | 25 | |
3971886a AC |
26 | #ifdef HAVE_STRING_H |
27 | #include <string.h> | |
28 | #else | |
29 | #ifdef HAVE_STRINGS_H | |
30 | #include <strings.h> | |
31 | #endif | |
32 | #endif | |
33 | ||
7b167b09 MM |
34 | #ifndef SIZE_PHASE |
35 | #define SIZE_PHASE 8 | |
36 | #endif | |
37 | ||
a7724171 MM |
38 | #ifndef SIZE_LOCATION |
39 | #define SIZE_LOCATION 20 | |
40 | #endif | |
41 | ||
42 | #ifndef SIZE_PC | |
43 | #define SIZE_PC 6 | |
44 | #endif | |
45 | ||
46 | #ifndef SIZE_LINE_NUMBER | |
47 | #define SIZE_LINE_NUMBER 4 | |
48 | #endif | |
49 | ||
3971886a AC |
50 | static MODULE_UNINSTALL_FN trace_uninstall; |
51 | ||
52 | static DECLARE_OPTION_HANDLER (trace_option_handler); | |
53 | ||
7b167b09 MM |
54 | enum { |
55 | OPTION_TRACE_INSN = OPTION_START, | |
56 | OPTION_TRACE_DECODE, | |
57 | OPTION_TRACE_EXTRACT, | |
58 | OPTION_TRACE_LINENUM, | |
59 | OPTION_TRACE_MEMORY, | |
60 | OPTION_TRACE_MODEL, | |
61 | OPTION_TRACE_ALU, | |
62 | OPTION_TRACE_CORE, | |
63 | OPTION_TRACE_EVENTS, | |
64 | OPTION_TRACE_FPU, | |
65 | OPTION_TRACE_BRANCH, | |
66 | OPTION_TRACE_SEMANTICS, | |
67 | OPTION_TRACE_FILE | |
68 | }; | |
3971886a AC |
69 | |
70 | static const OPTION trace_options[] = | |
71 | { | |
72 | { {"trace", no_argument, NULL, 't'}, | |
73 | 't', NULL, "Perform tracing", | |
74 | trace_option_handler }, | |
75 | { {"trace-insn", no_argument, NULL, OPTION_TRACE_INSN}, | |
76 | '\0', NULL, "Perform instruction tracing", | |
77 | trace_option_handler }, | |
78 | { {"trace-decode", no_argument, NULL, OPTION_TRACE_DECODE}, | |
79 | '\0', NULL, "Perform instruction decoding tracing", | |
80 | trace_option_handler }, | |
81 | { {"trace-extract", no_argument, NULL, OPTION_TRACE_EXTRACT}, | |
82 | '\0', NULL, "Perform instruction extraction tracing", | |
83 | trace_option_handler }, | |
84 | { {"trace-linenum", no_argument, NULL, OPTION_TRACE_LINENUM}, | |
a7724171 | 85 | '\0', NULL, "Perform line number tracing (implies --trace-insn)", |
3971886a AC |
86 | trace_option_handler }, |
87 | { {"trace-memory", no_argument, NULL, OPTION_TRACE_MEMORY}, | |
88 | '\0', NULL, "Perform memory tracing", | |
89 | trace_option_handler }, | |
90 | { {"trace-model", no_argument, NULL, OPTION_TRACE_MODEL}, | |
91 | '\0', NULL, "Perform model tracing", | |
92 | trace_option_handler }, | |
93 | { {"trace-alu", no_argument, NULL, OPTION_TRACE_ALU}, | |
94 | '\0', NULL, "Perform ALU tracing", | |
95 | trace_option_handler }, | |
96 | { {"trace-core", no_argument, NULL, OPTION_TRACE_CORE}, | |
97 | '\0', NULL, "Perform CORE tracing", | |
98 | trace_option_handler }, | |
99 | { {"trace-events", no_argument, NULL, OPTION_TRACE_EVENTS}, | |
100 | '\0', NULL, "Perform EVENTS tracing", | |
101 | trace_option_handler }, | |
102 | { {"trace-fpu", no_argument, NULL, OPTION_TRACE_FPU}, | |
103 | '\0', NULL, "Perform FPU tracing", | |
104 | trace_option_handler }, | |
7b167b09 MM |
105 | { {"trace-branch", no_argument, NULL, OPTION_TRACE_BRANCH}, |
106 | '\0', NULL, "Perform branch tracing", | |
107 | trace_option_handler }, | |
108 | { {"trace-semantics", no_argument, NULL, OPTION_TRACE_SEMANTICS}, | |
109 | '\0', NULL, "Perform ALU, FPU, and MEMORY tracing", | |
110 | trace_option_handler }, | |
3971886a AC |
111 | { {"trace-file", required_argument, NULL, OPTION_TRACE_FILE}, |
112 | '\0', "FILE NAME", "Specify tracing output file", | |
113 | trace_option_handler }, | |
114 | { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } | |
115 | }; | |
116 | ||
117 | static SIM_RC | |
118 | trace_option_handler (sd, opt, arg) | |
119 | SIM_DESC sd; | |
120 | int opt; | |
121 | char *arg; | |
122 | { | |
123 | int i,n; | |
124 | ||
125 | switch (opt) | |
126 | { | |
127 | case 't' : | |
128 | if (! WITH_TRACE) | |
129 | sim_io_eprintf (sd, "Tracing not compiled in, `-t' ignored\n"); | |
130 | else | |
131 | { | |
132 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
133 | for (i = 0; i < MAX_TRACE_VALUES; ++i) | |
134 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[i] = 1; | |
135 | STATE_CORE(sd)->trace = 1; | |
136 | STATE_EVENTS(sd)->trace = 1; | |
137 | } | |
138 | break; | |
139 | ||
140 | case OPTION_TRACE_INSN : | |
141 | if (WITH_TRACE_INSN_P) | |
142 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
143 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_INSN_IDX] = 1; | |
144 | else | |
145 | sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-insn' ignored\n"); | |
146 | break; | |
147 | ||
148 | case OPTION_TRACE_DECODE : | |
149 | if (WITH_TRACE_DECODE_P) | |
150 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
151 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_DECODE_IDX] = 1; | |
152 | else | |
153 | sim_io_eprintf (sd, "Decode tracing not compiled in, `--trace-decode' ignored\n"); | |
154 | break; | |
155 | ||
156 | case OPTION_TRACE_EXTRACT : | |
157 | if (WITH_TRACE_EXTRACT_P) | |
158 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
159 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_EXTRACT_IDX] = 1; | |
160 | else | |
161 | sim_io_eprintf (sd, "Extract tracing not compiled in, `--trace-extract' ignored\n"); | |
162 | break; | |
163 | ||
164 | case OPTION_TRACE_LINENUM : | |
a7724171 | 165 | if (WITH_TRACE_LINENUM_P && WITH_TRACE_INSN_P) |
3971886a | 166 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) |
a7724171 MM |
167 | { |
168 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_LINENUM_IDX] = 1; | |
169 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_INSN_IDX] = 1; | |
170 | } | |
3971886a | 171 | else |
a7724171 | 172 | sim_io_eprintf (sd, "Line number or instruction tracing not compiled in, `--trace-linenum' ignored\n"); |
3971886a AC |
173 | break; |
174 | ||
175 | case OPTION_TRACE_MEMORY : | |
176 | if (WITH_TRACE_MEMORY_P) | |
177 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
178 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_MEMORY_IDX] = 1; | |
179 | else | |
180 | sim_io_eprintf (sd, "Memory tracing not compiled in, `--trace-memory' ignored\n"); | |
181 | break; | |
182 | ||
183 | case OPTION_TRACE_MODEL : | |
184 | if (WITH_TRACE_MODEL_P) | |
185 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
186 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_MODEL_IDX] = 1; | |
187 | else | |
188 | sim_io_eprintf (sd, "Model tracing not compiled in, `--trace-model' ignored\n"); | |
189 | break; | |
190 | ||
191 | case OPTION_TRACE_ALU : | |
192 | if (WITH_TRACE_ALU_P) | |
193 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
194 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_ALU_IDX] = 1; | |
195 | else | |
196 | sim_io_eprintf (sd, "ALU tracing not compiled in, `--trace-alu' ignored\n"); | |
197 | break; | |
198 | ||
199 | case OPTION_TRACE_CORE : | |
200 | if (WITH_TRACE_CORE_P) | |
201 | { | |
202 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
203 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_CORE_IDX] = 1; | |
204 | STATE_CORE(sd)->trace = 1; | |
205 | } | |
206 | else | |
207 | sim_io_eprintf (sd, "CORE tracing not compiled in, `--trace-core' ignored\n"); | |
208 | break; | |
209 | ||
210 | case OPTION_TRACE_EVENTS : | |
211 | if (WITH_TRACE_EVENTS_P) | |
212 | { | |
213 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
214 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_EVENTS_IDX] = 1; | |
215 | STATE_EVENTS(sd)->trace = 1; | |
216 | } | |
217 | else | |
218 | sim_io_eprintf (sd, "EVENTS tracing not compiled in, `--trace-events' ignored\n"); | |
219 | break; | |
220 | ||
221 | case OPTION_TRACE_FPU : | |
222 | if (WITH_TRACE_FPU_P) | |
223 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
224 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_FPU_IDX] = 1; | |
225 | else | |
226 | sim_io_eprintf (sd, "FPU tracing not compiled in, `--trace-fpu' ignored\n"); | |
227 | break; | |
228 | ||
7b167b09 MM |
229 | case OPTION_TRACE_BRANCH : |
230 | if (WITH_TRACE_BRANCH_P) | |
231 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
232 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_FPU_IDX] = 1; | |
233 | else | |
234 | sim_io_eprintf (sd, "Branch tracing not compiled in, `--trace-branch' ignored\n"); | |
235 | break; | |
236 | ||
237 | case OPTION_TRACE_SEMANTICS : | |
238 | if (WITH_TRACE_ALU_P && WITH_TRACE_FPU_P && WITH_TRACE_MEMORY_P) | |
239 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
240 | { | |
241 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_ALU_IDX] = 1; | |
242 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_FPU_IDX] = 1; | |
243 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_MEMORY_IDX] = 1; | |
244 | CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_BRANCH_IDX] = 1; | |
245 | } | |
246 | else | |
247 | sim_io_eprintf (sd, "Alu, fpu, and/or memory tracing not compiled in, `--trace-semantics' ignored\n"); | |
248 | break; | |
249 | ||
3971886a AC |
250 | case OPTION_TRACE_FILE : |
251 | if (! WITH_TRACE) | |
252 | sim_io_eprintf (sd, "Tracing not compiled in, `--trace-file' ignored\n"); | |
253 | else | |
254 | { | |
255 | FILE *f = fopen (arg, "w"); | |
256 | ||
257 | if (f == NULL) | |
258 | { | |
259 | sim_io_eprintf (sd, "Unable to open trace output file `%s'\n", arg); | |
260 | return SIM_RC_FAIL; | |
261 | } | |
262 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
263 | TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, n))) = f; | |
264 | } | |
265 | break; | |
266 | } | |
267 | ||
268 | return SIM_RC_OK; | |
269 | } | |
270 | \f | |
271 | /* Install tracing support. */ | |
272 | ||
273 | SIM_RC | |
274 | trace_install (SIM_DESC sd) | |
275 | { | |
276 | int i; | |
277 | ||
278 | sim_add_option_table (sd, trace_options); | |
279 | for (i = 0; i < MAX_NR_PROCESSORS; ++i) | |
280 | memset (CPU_TRACE_DATA (STATE_CPU (sd, i)), 0, | |
281 | sizeof (* CPU_TRACE_DATA (STATE_CPU (sd, i)))); | |
282 | sim_module_add_uninstall_fn (sd, trace_uninstall); | |
283 | return SIM_RC_OK; | |
284 | } | |
285 | ||
286 | static void | |
287 | trace_uninstall (SIM_DESC sd) | |
288 | { | |
ea4e4493 | 289 | int i,j; |
3971886a AC |
290 | |
291 | for (i = 0; i < MAX_NR_PROCESSORS; ++i) | |
292 | { | |
293 | TRACE_DATA *data = CPU_TRACE_DATA (STATE_CPU (sd, i)); | |
294 | if (TRACE_FILE (data) != NULL) | |
ea4e4493 DE |
295 | { |
296 | /* If output from different cpus is going to the same file, | |
297 | avoid closing the file twice. */ | |
298 | for (j = 0; j < i; ++j) | |
299 | if (TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, j))) | |
300 | == TRACE_FILE (data)) | |
301 | break; | |
302 | if (i == j) | |
303 | fclose (TRACE_FILE (data)); | |
304 | } | |
3971886a AC |
305 | } |
306 | } | |
307 | \f | |
e9b2f579 | 308 | void |
d0adfefd | 309 | trace_one_insn (SIM_DESC sd, sim_cpu *cpu, address_word pc, |
7b167b09 | 310 | int line_p, const char *filename, int linenum, |
381f42ef AC |
311 | const char *phase_wo_colon, const char *fmt, |
312 | ...) | |
a7724171 | 313 | { |
381f42ef | 314 | va_list ap; |
7b167b09 MM |
315 | char phase[SIZE_PHASE+2]; |
316 | ||
317 | strncpy (phase, phase_wo_colon, SIZE_PHASE); | |
318 | strcat (phase, ":"); | |
319 | ||
d0adfefd | 320 | if (!line_p) |
381f42ef AC |
321 | { |
322 | trace_printf (sd, cpu, "%-*s %s:%-*d 0x%.*lx ", | |
323 | SIZE_PHASE+1, phase, | |
324 | filename, | |
325 | SIZE_LINE_NUMBER, linenum, | |
326 | SIZE_PC, (long)pc); | |
327 | va_start (ap, fmt); | |
328 | trace_vprintf (sd, cpu, fmt, ap); | |
329 | va_end (ap); | |
330 | trace_printf (sd, cpu, "\n"); | |
331 | } | |
a7724171 MM |
332 | else |
333 | { | |
334 | char buf[256]; | |
335 | ||
336 | buf[0] = 0; | |
337 | if (STATE_TEXT_SECTION (CPU_STATE (cpu)) | |
338 | && pc >= STATE_TEXT_START (CPU_STATE (cpu)) | |
339 | && pc < STATE_TEXT_END (CPU_STATE (cpu))) | |
340 | { | |
341 | const char *pc_filename = (const char *)0; | |
342 | const char *pc_function = (const char *)0; | |
343 | unsigned int pc_linenum = 0; | |
344 | ||
345 | if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)), | |
346 | STATE_TEXT_SECTION (CPU_STATE (cpu)), | |
347 | (struct symbol_cache_entry **) 0, | |
348 | pc - STATE_TEXT_START (CPU_STATE (cpu)), | |
349 | &pc_filename, &pc_function, &pc_linenum)) | |
350 | { | |
351 | char *p = buf; | |
352 | if (pc_linenum) | |
353 | { | |
354 | sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, pc_linenum); | |
355 | p += strlen (p); | |
356 | } | |
357 | else | |
358 | { | |
359 | sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---"); | |
360 | p += SIZE_LINE_NUMBER+2; | |
361 | } | |
362 | ||
363 | if (pc_function) | |
364 | { | |
365 | sprintf (p, "%s ", pc_function); | |
366 | p += strlen (p); | |
367 | } | |
d0adfefd | 368 | else if (pc_filename) |
a7724171 | 369 | { |
d0adfefd MM |
370 | char *q = (char *) strrchr (pc_filename, '/'); |
371 | sprintf (p, "%s ", (q) ? q+1 : pc_filename); | |
a7724171 MM |
372 | p += strlen (p); |
373 | } | |
374 | ||
375 | if (*p == ' ') | |
376 | *p = '\0'; | |
377 | } | |
378 | } | |
379 | ||
381f42ef | 380 | trace_printf (sd, cpu, "%-*s 0x%.*x %-*.*s ", |
7b167b09 | 381 | SIZE_PHASE+1, phase, |
a7724171 | 382 | SIZE_PC, (unsigned) pc, |
381f42ef AC |
383 | SIZE_LOCATION, SIZE_LOCATION, buf); |
384 | va_start (ap, fmt); | |
385 | trace_vprintf (sd, cpu, fmt, ap); | |
386 | va_end (ap); | |
387 | trace_printf (sd, cpu, "\n"); | |
a7724171 MM |
388 | } |
389 | } | |
390 | \f | |
381f42ef AC |
391 | void |
392 | trace_vprintf (SIM_DESC sd, sim_cpu *cpu, const char *fmt, va_list ap) | |
393 | { | |
394 | if (cpu != NULL && TRACE_FILE (CPU_TRACE_DATA (cpu)) != NULL) | |
395 | vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, ap); | |
396 | else | |
397 | sim_io_evprintf (sd, fmt, ap); | |
398 | } | |
399 | ||
a7724171 | 400 | void |
3971886a | 401 | trace_printf VPARAMS ((SIM_DESC sd, sim_cpu *cpu, const char *fmt, ...)) |
e9b2f579 DE |
402 | { |
403 | #ifndef __STDC__ | |
3971886a | 404 | SIM_DESC sd; |
e9b2f579 DE |
405 | sim_cpu *cpu; |
406 | const char *fmt; | |
407 | #endif | |
408 | va_list ap; | |
409 | ||
410 | VA_START (ap, fmt); | |
411 | #ifndef __STDC__ | |
3971886a | 412 | sd = va_arg (ap, SIM_DESC); |
e9b2f579 DE |
413 | cpu = va_arg (ap, sim_cpu *); |
414 | fmt = va_arg (ap, const char *); | |
415 | #endif | |
416 | ||
381f42ef | 417 | trace_vprintf (sd, cpu, fmt, ap); |
e9b2f579 DE |
418 | |
419 | va_end (ap); | |
420 | } | |
421 | ||
422 | void | |
423 | debug_printf VPARAMS ((sim_cpu *cpu, const char *fmt, ...)) | |
424 | { | |
425 | #ifndef __STDC__ | |
426 | sim_cpu *cpu; | |
427 | const char *fmt; | |
428 | #endif | |
429 | va_list ap; | |
430 | ||
431 | VA_START (ap, fmt); | |
432 | #ifndef __STDC__ | |
433 | cpu = va_arg (ap, sim_cpu *); | |
434 | fmt = va_arg (ap, const char *); | |
435 | #endif | |
436 | ||
437 | if (CPU_DEBUG_FILE (cpu) == NULL) | |
438 | (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered) | |
439 | (STATE_CALLBACK (CPU_STATE (cpu)), fmt, ap); | |
440 | else | |
441 | vfprintf (CPU_DEBUG_FILE (cpu), fmt, ap); | |
442 | ||
443 | va_end (ap); | |
444 | } |