nuke lseek
[deliverable/binutils-gdb.git] / sim / common / sim-trace.c
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"
23 #include "sim-options.h"
24 #include "bfd.h"
25
26 #include "sim-assert.h"
27
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #else
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
34 #endif
35
36 #ifndef SIZE_PHASE
37 #define SIZE_PHASE 8
38 #endif
39
40 #ifndef SIZE_LOCATION
41 #define SIZE_LOCATION 20
42 #endif
43
44 #ifndef SIZE_PC
45 #define SIZE_PC 6
46 #endif
47
48 #ifndef SIZE_LINE_NUMBER
49 #define SIZE_LINE_NUMBER 4
50 #endif
51
52 static MODULE_UNINSTALL_FN trace_uninstall;
53
54 static DECLARE_OPTION_HANDLER (trace_option_handler);
55
56 enum {
57 OPTION_TRACE_INSN = OPTION_START,
58 OPTION_TRACE_DECODE,
59 OPTION_TRACE_EXTRACT,
60 OPTION_TRACE_LINENUM,
61 OPTION_TRACE_MEMORY,
62 OPTION_TRACE_MODEL,
63 OPTION_TRACE_ALU,
64 OPTION_TRACE_CORE,
65 OPTION_TRACE_EVENTS,
66 OPTION_TRACE_FPU,
67 OPTION_TRACE_BRANCH,
68 OPTION_TRACE_SEMANTICS,
69 OPTION_TRACE_DEBUG,
70 OPTION_TRACE_FILE
71 };
72
73 static const OPTION trace_options[] =
74 {
75 { {"trace", optional_argument, NULL, 't'},
76 't', "on|off", "Perform tracing",
77 trace_option_handler },
78 { {"trace-insn", optional_argument, NULL, OPTION_TRACE_INSN},
79 '\0', "on|off", "Perform instruction tracing",
80 trace_option_handler },
81 { {"trace-decode", optional_argument, NULL, OPTION_TRACE_DECODE},
82 '\0', "on|off", "Perform instruction decoding tracing",
83 trace_option_handler },
84 { {"trace-extract", optional_argument, NULL, OPTION_TRACE_EXTRACT},
85 '\0', "on|off", "Perform instruction extraction tracing",
86 trace_option_handler },
87 { {"trace-linenum", optional_argument, NULL, OPTION_TRACE_LINENUM},
88 '\0', "on|off", "Perform line number tracing (implies --trace-insn)",
89 trace_option_handler },
90 { {"trace-memory", optional_argument, NULL, OPTION_TRACE_MEMORY},
91 '\0', "on|off", "Perform memory tracing",
92 trace_option_handler },
93 { {"trace-model", optional_argument, NULL, OPTION_TRACE_MODEL},
94 '\0', "on|off", "Perform model tracing",
95 trace_option_handler },
96 { {"trace-alu", optional_argument, NULL, OPTION_TRACE_ALU},
97 '\0', "on|off", "Perform ALU tracing",
98 trace_option_handler },
99 { {"trace-core", optional_argument, NULL, OPTION_TRACE_CORE},
100 '\0', "on|off", "Perform CORE tracing",
101 trace_option_handler },
102 { {"trace-events", optional_argument, NULL, OPTION_TRACE_EVENTS},
103 '\0', "on|off", "Perform EVENTS tracing",
104 trace_option_handler },
105 { {"trace-fpu", optional_argument, NULL, OPTION_TRACE_FPU},
106 '\0', "on|off", "Perform FPU tracing",
107 trace_option_handler },
108 { {"trace-branch", optional_argument, NULL, OPTION_TRACE_BRANCH},
109 '\0', "on|off", "Perform branch tracing",
110 trace_option_handler },
111 { {"trace-semantics", optional_argument, NULL, OPTION_TRACE_SEMANTICS},
112 '\0', "on|off", "Perform ALU, FPU, MEMORY, and BRANCH tracing",
113 trace_option_handler },
114 { {"trace-debug", optional_argument, NULL, OPTION_TRACE_DEBUG},
115 '\0', "on|off", "Add information useful for debugging the simulator to the tracing output",
116 trace_option_handler },
117 { {"trace-file", required_argument, NULL, OPTION_TRACE_FILE},
118 '\0', "FILE NAME", "Specify tracing output file",
119 trace_option_handler },
120 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
121 };
122
123
124 /* Set FIRST_TRACE .. LAST_TRACE according to arg. At least
125 FIRST_TRACE is always set */
126
127 static SIM_RC
128 set_trace_options (sd, name, first_trace, last_trace, arg)
129 SIM_DESC sd;
130 const char *name;
131 int first_trace;
132 int last_trace;
133 const char *arg;
134 {
135 int trace_nr;
136 int cpu_nr;
137 int trace_val = 1;
138
139 if (arg != NULL)
140 {
141 if (strcmp (arg, "yes") == 0
142 || strcmp (arg, "on") == 0
143 || strcmp (arg, "1") == 0)
144 trace_val = 1;
145 else if (strcmp (arg, "no") == 0
146 || strcmp (arg, "off") == 0
147 || strcmp (arg, "0") == 0)
148 trace_val = 0;
149 else
150 {
151 sim_io_eprintf (sd, "Argument `%s' for `--trace%s' invalid, one of `on', `off', `yes', `no' expected\n", arg, name);
152 return SIM_RC_FAIL;
153 }
154 }
155
156 trace_nr = first_trace;
157 do
158 {
159 /* Set non-cpu specific values. */
160 switch (trace_nr)
161 {
162 case TRACE_EVENTS_IDX:
163 STATE_EVENTS (sd)->trace = trace_val;
164 break;
165 case TRACE_DEBUG_IDX:
166 STATE_TRACE_FLAGS (sd)[trace_nr] = trace_val;
167 break;
168 }
169
170 /* Set cpu values. */
171 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
172 {
173 CPU_TRACE_FLAGS (STATE_CPU (sd, cpu_nr))[trace_nr] = trace_val;
174 }
175 }
176 while (++trace_nr < last_trace);
177
178 return SIM_RC_OK;
179 }
180
181
182 static SIM_RC
183 trace_option_handler (sd, opt, arg, is_command)
184 SIM_DESC sd;
185 int opt;
186 char *arg;
187 int is_command;
188 {
189 int n;
190
191 switch (opt)
192 {
193 case 't' :
194 if (! WITH_TRACE)
195 sim_io_eprintf (sd, "Tracing not compiled in, `-t' ignored\n");
196 else
197 return set_trace_options (sd, "trace", 0, MAX_TRACE_VALUES, arg);
198 break;
199
200 case OPTION_TRACE_INSN :
201 if (WITH_TRACE_INSN_P)
202 return set_trace_options (sd, "-insn", TRACE_INSN_IDX, -1, arg);
203 else
204 sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-insn' ignored\n");
205 break;
206
207 case OPTION_TRACE_DECODE :
208 if (WITH_TRACE_DECODE_P)
209 return set_trace_options (sd, "-decode", TRACE_DECODE_IDX, -1, arg);
210 else
211 sim_io_eprintf (sd, "Decode tracing not compiled in, `--trace-decode' ignored\n");
212 break;
213
214 case OPTION_TRACE_EXTRACT :
215 if (WITH_TRACE_EXTRACT_P)
216 return set_trace_options (sd, "-extract", TRACE_EXTRACT_IDX, -1, arg);
217 else
218 sim_io_eprintf (sd, "Extract tracing not compiled in, `--trace-extract' ignored\n");
219 break;
220
221 case OPTION_TRACE_LINENUM :
222 if (WITH_TRACE_LINENUM_P && WITH_TRACE_INSN_P)
223 {
224 if (set_trace_options (sd, "-linenum", TRACE_LINENUM_IDX, -1, arg) != SIM_RC_OK
225 || set_trace_options (sd, "-linenum", TRACE_INSN_IDX, -1, arg) != SIM_RC_OK)
226 return SIM_RC_FAIL;
227 }
228 else
229 sim_io_eprintf (sd, "Line number or instruction tracing not compiled in, `--trace-linenum' ignored\n");
230 break;
231
232 case OPTION_TRACE_MEMORY :
233 if (WITH_TRACE_MEMORY_P)
234 return set_trace_options (sd, "-memory", TRACE_MEMORY_IDX, -1, arg);
235 else
236 sim_io_eprintf (sd, "Memory tracing not compiled in, `--trace-memory' ignored\n");
237 break;
238
239 case OPTION_TRACE_MODEL :
240 if (WITH_TRACE_MODEL_P)
241 return set_trace_options (sd, "-model", TRACE_MODEL_IDX, -1, arg);
242 else
243 sim_io_eprintf (sd, "Model tracing not compiled in, `--trace-model' ignored\n");
244 break;
245
246 case OPTION_TRACE_ALU :
247 if (WITH_TRACE_ALU_P)
248 return set_trace_options (sd, "-alu", TRACE_ALU_IDX, -1, arg);
249 else
250 sim_io_eprintf (sd, "ALU tracing not compiled in, `--trace-alu' ignored\n");
251 break;
252
253 case OPTION_TRACE_CORE :
254 if (WITH_TRACE_CORE_P)
255 return set_trace_options (sd, "-core", TRACE_CORE_IDX, -1, arg);
256 else
257 sim_io_eprintf (sd, "CORE tracing not compiled in, `--trace-core' ignored\n");
258 break;
259
260 case OPTION_TRACE_EVENTS :
261 if (WITH_TRACE_EVENTS_P)
262 return set_trace_options (sd, "-events", TRACE_EVENTS_IDX, -1, arg);
263 else
264 sim_io_eprintf (sd, "EVENTS tracing not compiled in, `--trace-events' ignored\n");
265 break;
266
267 case OPTION_TRACE_FPU :
268 if (WITH_TRACE_FPU_P)
269 return set_trace_options (sd, "-fpu", TRACE_FPU_IDX, -1, arg);
270 else
271 sim_io_eprintf (sd, "FPU tracing not compiled in, `--trace-fpu' ignored\n");
272 break;
273
274 case OPTION_TRACE_BRANCH :
275 if (WITH_TRACE_BRANCH_P)
276 return set_trace_options (sd, "-branch", TRACE_BRANCH_IDX, -1, arg);
277 else
278 sim_io_eprintf (sd, "Branch tracing not compiled in, `--trace-branch' ignored\n");
279 break;
280
281 case OPTION_TRACE_SEMANTICS :
282 if (WITH_TRACE_ALU_P
283 && WITH_TRACE_FPU_P
284 && WITH_TRACE_MEMORY_P
285 && WITH_TRACE_BRANCH_P)
286 {
287 if (set_trace_options (sd, "-semantics", TRACE_ALU_IDX, -1, arg) != SIM_RC_OK
288 || set_trace_options (sd, "-semantics", TRACE_FPU_IDX, -1, arg) != SIM_RC_OK
289 || set_trace_options (sd, "-semantics", TRACE_MEMORY_IDX, -1, arg) != SIM_RC_OK
290 || set_trace_options (sd, "-semantics", TRACE_BRANCH_IDX, -1, arg) != SIM_RC_OK)
291 return SIM_RC_FAIL;
292 }
293 else
294 sim_io_eprintf (sd, "Alu, fpu, memory, and/or branch tracing not compiled in, `--trace-semantics' ignored\n");
295 break;
296
297 case OPTION_TRACE_DEBUG :
298 if (WITH_TRACE_DEBUG_P)
299 return set_trace_options (sd, "-debug", TRACE_DEBUG_IDX, -1, arg);
300 else
301 sim_io_eprintf (sd, "Tracing debug support not compiled in, `--trace-debug' ignored\n");
302 break;
303
304 case OPTION_TRACE_FILE :
305 if (! WITH_TRACE)
306 sim_io_eprintf (sd, "Tracing not compiled in, `--trace-file' ignored\n");
307 else
308 {
309 FILE *f = fopen (arg, "w");
310
311 if (f == NULL)
312 {
313 sim_io_eprintf (sd, "Unable to open trace output file `%s'\n", arg);
314 return SIM_RC_FAIL;
315 }
316 for (n = 0; n < MAX_NR_PROCESSORS; ++n)
317 TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, n))) = f;
318 TRACE_FILE (STATE_TRACE_DATA (sd)) = f;
319 }
320 break;
321 }
322
323 return SIM_RC_OK;
324 }
325 \f
326 /* Install tracing support. */
327
328 SIM_RC
329 trace_install (SIM_DESC sd)
330 {
331 int i;
332
333 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
334
335 sim_add_option_table (sd, trace_options);
336 memset (STATE_TRACE_DATA (sd), 0, sizeof (* STATE_TRACE_DATA (sd)));
337 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
338 memset (CPU_TRACE_DATA (STATE_CPU (sd, i)), 0,
339 sizeof (* CPU_TRACE_DATA (STATE_CPU (sd, i))));
340 sim_module_add_uninstall_fn (sd, trace_uninstall);
341 return SIM_RC_OK;
342 }
343
344 static void
345 trace_uninstall (SIM_DESC sd)
346 {
347 int i,j;
348 FILE *sfile = TRACE_FILE (STATE_TRACE_DATA (sd));
349
350 if (sfile != NULL)
351 fclose (sfile);
352
353 for (i = 0; i < MAX_NR_PROCESSORS; ++i)
354 {
355 FILE *cfile = TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, i)));
356 if (cfile != NULL && cfile != sfile)
357 {
358 /* If output from different cpus is going to the same file,
359 avoid closing the file twice. */
360 for (j = 0; j < i; ++j)
361 if (TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, j))) == cfile)
362 break;
363 if (i == j)
364 fclose (cfile);
365 }
366 }
367 }
368 \f
369 void
370 trace_one_insn (SIM_DESC sd, sim_cpu *cpu, address_word pc,
371 int line_p, const char *filename, int linenum,
372 const char *phase_wo_colon, const char *fmt,
373 ...)
374 {
375 va_list ap;
376 char phase[SIZE_PHASE+2];
377
378 strncpy (phase, phase_wo_colon, SIZE_PHASE);
379 strcat (phase, ":");
380
381 if (!line_p)
382 {
383 trace_printf (sd, cpu, "%-*s %s:%-*d 0x%.*lx ",
384 SIZE_PHASE+1, phase,
385 filename,
386 SIZE_LINE_NUMBER, linenum,
387 SIZE_PC, (long)pc);
388 va_start (ap, fmt);
389 trace_vprintf (sd, cpu, fmt, ap);
390 va_end (ap);
391 trace_printf (sd, cpu, "\n");
392 }
393 else
394 {
395 char buf[256];
396
397 buf[0] = 0;
398 if (STATE_TEXT_SECTION (CPU_STATE (cpu))
399 && pc >= STATE_TEXT_START (CPU_STATE (cpu))
400 && pc < STATE_TEXT_END (CPU_STATE (cpu)))
401 {
402 const char *pc_filename = (const char *)0;
403 const char *pc_function = (const char *)0;
404 unsigned int pc_linenum = 0;
405
406 if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)),
407 STATE_TEXT_SECTION (CPU_STATE (cpu)),
408 (struct symbol_cache_entry **) 0,
409 pc - STATE_TEXT_START (CPU_STATE (cpu)),
410 &pc_filename, &pc_function, &pc_linenum))
411 {
412 char *p = buf;
413 if (pc_linenum)
414 {
415 sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, pc_linenum);
416 p += strlen (p);
417 }
418 else
419 {
420 sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---");
421 p += SIZE_LINE_NUMBER+2;
422 }
423
424 if (pc_function)
425 {
426 sprintf (p, "%s ", pc_function);
427 p += strlen (p);
428 }
429 else if (pc_filename)
430 {
431 char *q = (char *) strrchr (pc_filename, '/');
432 sprintf (p, "%s ", (q) ? q+1 : pc_filename);
433 p += strlen (p);
434 }
435
436 if (*p == ' ')
437 *p = '\0';
438 }
439 }
440
441 trace_printf (sd, cpu, "%-*s 0x%.*x %-*.*s ",
442 SIZE_PHASE+1, phase,
443 SIZE_PC, (unsigned) pc,
444 SIZE_LOCATION, SIZE_LOCATION, buf);
445 va_start (ap, fmt);
446 trace_vprintf (sd, cpu, fmt, ap);
447 va_end (ap);
448 trace_printf (sd, cpu, "\n");
449 }
450 }
451 \f
452 void
453 trace_vprintf (SIM_DESC sd, sim_cpu *cpu, const char *fmt, va_list ap)
454 {
455 if (cpu != NULL)
456 {
457 if (TRACE_FILE (CPU_TRACE_DATA (cpu)) != NULL)
458 vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, ap);
459 else
460 sim_io_evprintf (sd, fmt, ap);
461 }
462 else
463 {
464 if (TRACE_FILE (STATE_TRACE_DATA (sd)) != NULL)
465 vfprintf (TRACE_FILE (STATE_TRACE_DATA (sd)), fmt, ap);
466 else
467 sim_io_evprintf (sd, fmt, ap);
468 }
469 }
470
471 void
472 trace_printf VPARAMS ((SIM_DESC sd, sim_cpu *cpu, const char *fmt, ...))
473 {
474 #if !defined __STDC__ && !defined ALMOST_STDC
475 SIM_DESC sd;
476 sim_cpu *cpu;
477 const char *fmt;
478 #endif
479 va_list ap;
480
481 VA_START (ap, fmt);
482 #if !defined __STDC__ && !defined ALMOST_STDC
483 sd = va_arg (ap, SIM_DESC);
484 cpu = va_arg (ap, sim_cpu *);
485 fmt = va_arg (ap, const char *);
486 #endif
487
488 trace_vprintf (sd, cpu, fmt, ap);
489
490 va_end (ap);
491 }
492
493 void
494 debug_printf VPARAMS ((sim_cpu *cpu, const char *fmt, ...))
495 {
496 #if !defined __STDC__ && !defined ALMOST_STDC
497 sim_cpu *cpu;
498 const char *fmt;
499 #endif
500 va_list ap;
501
502 VA_START (ap, fmt);
503 #if !defined __STDC__ && !defined ALMOST_STDC
504 cpu = va_arg (ap, sim_cpu *);
505 fmt = va_arg (ap, const char *);
506 #endif
507
508 if (CPU_DEBUG_FILE (cpu) == NULL)
509 (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
510 (STATE_CALLBACK (CPU_STATE (cpu)), fmt, ap);
511 else
512 vfprintf (CPU_DEBUG_FILE (cpu), fmt, ap);
513
514 va_end (ap);
515 }
This page took 0.051841 seconds and 4 git commands to generate.