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