Enable --trace-linenum support
[platform/upstream/binutils.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 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
32 #endif
33
34 #ifndef SIZE_LOCATION
35 #define SIZE_LOCATION 20
36 #endif
37
38 #ifndef SIZE_PC
39 #define SIZE_PC 6
40 #endif
41
42 #ifndef SIZE_LINE_NUMBER
43 #define SIZE_LINE_NUMBER 4
44 #endif
45
46 static MODULE_UNINSTALL_FN trace_uninstall;
47
48 static DECLARE_OPTION_HANDLER (trace_option_handler);
49
50 #define OPTION_TRACE_INSN       (OPTION_START + 0)
51 #define OPTION_TRACE_DECODE     (OPTION_START + 1)
52 #define OPTION_TRACE_EXTRACT    (OPTION_START + 2)
53 #define OPTION_TRACE_LINENUM    (OPTION_START + 3)
54 #define OPTION_TRACE_MEMORY     (OPTION_START + 4)
55 #define OPTION_TRACE_MODEL      (OPTION_START + 5)
56 #define OPTION_TRACE_ALU        (OPTION_START + 6)
57 #define OPTION_TRACE_CORE       (OPTION_START + 7)
58 #define OPTION_TRACE_EVENTS     (OPTION_START + 8)
59 #define OPTION_TRACE_FPU        (OPTION_START + 9)
60 #define OPTION_TRACE_FILE       (OPTION_START + 10)
61
62 static const OPTION trace_options[] =
63 {
64   { {"trace", no_argument, NULL, 't'},
65       't', NULL, "Perform tracing",
66       trace_option_handler },
67   { {"trace-insn", no_argument, NULL, OPTION_TRACE_INSN},
68       '\0', NULL, "Perform instruction tracing",
69       trace_option_handler },
70   { {"trace-decode", no_argument, NULL, OPTION_TRACE_DECODE},
71       '\0', NULL, "Perform instruction decoding tracing",
72       trace_option_handler },
73   { {"trace-extract", no_argument, NULL, OPTION_TRACE_EXTRACT},
74       '\0', NULL, "Perform instruction extraction tracing",
75       trace_option_handler },
76   { {"trace-linenum", no_argument, NULL, OPTION_TRACE_LINENUM},
77       '\0', NULL, "Perform line number tracing (implies --trace-insn)",
78       trace_option_handler },
79   { {"trace-memory", no_argument, NULL, OPTION_TRACE_MEMORY},
80       '\0', NULL, "Perform memory tracing",
81       trace_option_handler },
82   { {"trace-model", no_argument, NULL, OPTION_TRACE_MODEL},
83       '\0', NULL, "Perform model tracing",
84       trace_option_handler },
85   { {"trace-alu", no_argument, NULL, OPTION_TRACE_ALU},
86       '\0', NULL, "Perform ALU tracing",
87       trace_option_handler },
88   { {"trace-core", no_argument, NULL, OPTION_TRACE_CORE},
89       '\0', NULL, "Perform CORE tracing",
90       trace_option_handler },
91   { {"trace-events", no_argument, NULL, OPTION_TRACE_EVENTS},
92       '\0', NULL, "Perform EVENTS tracing",
93       trace_option_handler },
94   { {"trace-fpu", no_argument, NULL, OPTION_TRACE_FPU},
95       '\0', NULL, "Perform FPU tracing",
96       trace_option_handler },
97   { {"trace-file", required_argument, NULL, OPTION_TRACE_FILE},
98       '\0', "FILE NAME", "Specify tracing output file",
99       trace_option_handler },
100   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
101 };
102
103 static SIM_RC
104 trace_option_handler (sd, opt, arg)
105      SIM_DESC sd;
106      int opt;
107      char *arg;
108 {
109   int i,n;
110
111   switch (opt)
112     {
113     case 't' :
114       if (! WITH_TRACE)
115         sim_io_eprintf (sd, "Tracing not compiled in, `-t' ignored\n");
116       else
117         {
118           for (n = 0; n < MAX_NR_PROCESSORS; ++n)
119             for (i = 0; i < MAX_TRACE_VALUES; ++i)
120               CPU_TRACE_FLAGS (STATE_CPU (sd, n))[i] = 1;
121           STATE_CORE(sd)->trace = 1;
122           STATE_EVENTS(sd)->trace = 1;
123         }
124       break;
125
126     case OPTION_TRACE_INSN :
127       if (WITH_TRACE_INSN_P)
128         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
129           CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_INSN_IDX] = 1;
130       else
131         sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-insn' ignored\n");
132       break;
133
134     case OPTION_TRACE_DECODE :
135       if (WITH_TRACE_DECODE_P)
136         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
137           CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_DECODE_IDX] = 1;
138       else
139         sim_io_eprintf (sd, "Decode tracing not compiled in, `--trace-decode' ignored\n");
140       break;
141
142     case OPTION_TRACE_EXTRACT :
143       if (WITH_TRACE_EXTRACT_P)
144         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
145           CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_EXTRACT_IDX] = 1;
146       else
147         sim_io_eprintf (sd, "Extract tracing not compiled in, `--trace-extract' ignored\n");
148       break;
149
150     case OPTION_TRACE_LINENUM :
151       if (WITH_TRACE_LINENUM_P && WITH_TRACE_INSN_P)
152         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
153           {
154             CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_LINENUM_IDX] = 1;
155             CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_INSN_IDX] = 1;
156           }
157       else
158         sim_io_eprintf (sd, "Line number or instruction tracing not compiled in, `--trace-linenum' ignored\n");
159       break;
160
161     case OPTION_TRACE_MEMORY :
162       if (WITH_TRACE_MEMORY_P)
163         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
164           CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_MEMORY_IDX] = 1;
165       else
166         sim_io_eprintf (sd, "Memory tracing not compiled in, `--trace-memory' ignored\n");
167       break;
168
169     case OPTION_TRACE_MODEL :
170       if (WITH_TRACE_MODEL_P)
171         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
172           CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_MODEL_IDX] = 1;
173       else
174         sim_io_eprintf (sd, "Model tracing not compiled in, `--trace-model' ignored\n");
175       break;
176
177     case OPTION_TRACE_ALU :
178       if (WITH_TRACE_ALU_P)
179         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
180           CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_ALU_IDX] = 1;
181       else
182         sim_io_eprintf (sd, "ALU tracing not compiled in, `--trace-alu' ignored\n");
183       break;
184
185     case OPTION_TRACE_CORE :
186       if (WITH_TRACE_CORE_P)
187         {
188           for (n = 0; n < MAX_NR_PROCESSORS; ++n)
189             CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_CORE_IDX] = 1;
190           STATE_CORE(sd)->trace = 1;
191         }
192       else
193         sim_io_eprintf (sd, "CORE tracing not compiled in, `--trace-core' ignored\n");
194       break;
195
196     case OPTION_TRACE_EVENTS :
197       if (WITH_TRACE_EVENTS_P)
198         {
199           for (n = 0; n < MAX_NR_PROCESSORS; ++n)
200             CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_EVENTS_IDX] = 1;
201           STATE_EVENTS(sd)->trace = 1;
202         }
203       else
204         sim_io_eprintf (sd, "EVENTS tracing not compiled in, `--trace-events' ignored\n");
205       break;
206
207     case OPTION_TRACE_FPU :
208       if (WITH_TRACE_FPU_P)
209         for (n = 0; n < MAX_NR_PROCESSORS; ++n)
210           CPU_TRACE_FLAGS (STATE_CPU (sd, n))[TRACE_FPU_IDX] = 1;
211       else
212         sim_io_eprintf (sd, "FPU tracing not compiled in, `--trace-fpu' ignored\n");
213       break;
214
215     case OPTION_TRACE_FILE :
216       if (! WITH_TRACE)
217         sim_io_eprintf (sd, "Tracing not compiled in, `--trace-file' ignored\n");
218       else
219         {
220           FILE *f = fopen (arg, "w");
221
222           if (f == NULL)
223             {
224               sim_io_eprintf (sd, "Unable to open trace output file `%s'\n", arg);
225               return SIM_RC_FAIL;
226             }
227           for (n = 0; n < MAX_NR_PROCESSORS; ++n)
228             TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, n))) = f;
229         }
230       break;
231     }
232
233   return SIM_RC_OK;
234 }
235 \f
236 /* Install tracing support.  */
237
238 SIM_RC
239 trace_install (SIM_DESC sd)
240 {
241   int i;
242
243   sim_add_option_table (sd, trace_options);
244   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
245     memset (CPU_TRACE_DATA (STATE_CPU (sd, i)), 0,
246             sizeof (* CPU_TRACE_DATA (STATE_CPU (sd, i))));
247   sim_module_add_uninstall_fn (sd, trace_uninstall);
248   return SIM_RC_OK;
249 }
250
251 static void
252 trace_uninstall (SIM_DESC sd)
253 {
254   int i;
255
256   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
257     {
258       TRACE_DATA *data = CPU_TRACE_DATA (STATE_CPU (sd, i));
259       if (TRACE_FILE (data) != NULL)
260         fclose (TRACE_FILE (data));
261     }
262 }
263 \f
264 void
265 trace_one_insn (SIM_DESC sd, sim_cpu *cpu, const char *filename, 
266                 int linenum, int idecode, address_word pc, const char *name)
267 {
268   if (idecode)
269     trace_printf(sd, cpu, "%s:%-*d 0x%.*lx (decode) %s\n",
270                  filename,
271                  SIZE_LINE_NUMBER, linenum,
272                  SIZE_PC, (long)pc,
273                  name);
274
275   else if (!TRACE_LINENUM_P (cpu))
276     trace_printf(sd, cpu, "%s:%-*d 0x%.*lx %s\n",
277                  filename,
278                  SIZE_LINE_NUMBER, linenum,
279                  SIZE_PC, (long)pc,
280                  name);
281
282   else
283     {
284       char buf[256];
285
286       buf[0] = 0;
287       if (STATE_TEXT_SECTION (CPU_STATE (cpu))
288           && pc >= STATE_TEXT_START (CPU_STATE (cpu))
289           && pc < STATE_TEXT_END (CPU_STATE (cpu)))
290         {
291           const char *pc_filename = (const char *)0;
292           const char *pc_function = (const char *)0;
293           unsigned int pc_linenum = 0;
294
295           if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)),
296                                      STATE_TEXT_SECTION (CPU_STATE (cpu)),
297                                      (struct symbol_cache_entry **) 0,
298                                      pc - STATE_TEXT_START (CPU_STATE (cpu)),
299                                      &pc_filename, &pc_function, &pc_linenum))
300             {
301               char *p = buf;
302               if (pc_linenum)
303                 {
304                   sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, pc_linenum);
305                   p += strlen (p);
306                 }
307               else
308                 {
309                   sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---");
310                   p += SIZE_LINE_NUMBER+2;
311                 }
312
313               if (pc_function)
314                 {
315                   sprintf (p, "%s ", pc_function);
316                   p += strlen (p);
317                 }
318               else if (filename)
319                 {
320                   char *q = (char *) strrchr (filename, '/');
321                   sprintf (p, "%s ", (q) ? q+1 : filename);
322                   p += strlen (p);
323                 }
324
325               if (*p == ' ')
326                 *p = '\0';
327             }
328         }
329
330       trace_printf (sd, cpu, "0x%.*x %-*.*s %s\n",
331                     SIZE_PC, (unsigned) pc,
332                     SIZE_LOCATION, SIZE_LOCATION, buf,
333                     name);
334     }
335 }
336 \f
337 void
338 trace_printf VPARAMS ((SIM_DESC sd, sim_cpu *cpu, const char *fmt, ...))
339 {
340 #ifndef __STDC__
341   SIM_DESC sd;
342   sim_cpu *cpu;
343   const char *fmt;
344 #endif
345   va_list ap;
346
347   VA_START (ap, fmt);
348 #ifndef __STDC__
349   sd = va_arg (ap, SIM_DESC);
350   cpu = va_arg (ap, sim_cpu *);
351   fmt = va_arg (ap, const char *);
352 #endif
353
354   if (cpu != NULL && TRACE_FILE (CPU_TRACE_DATA (cpu)) != NULL)
355     vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, ap);
356   else
357     sim_io_evprintf (sd, fmt, ap);
358
359   va_end (ap);
360 }
361
362 void
363 debug_printf VPARAMS ((sim_cpu *cpu, const char *fmt, ...))
364 {
365 #ifndef __STDC__
366   sim_cpu *cpu;
367   const char *fmt;
368 #endif
369   va_list ap;
370
371   VA_START (ap, fmt);
372 #ifndef __STDC__
373   cpu = va_arg (ap, sim_cpu *);
374   fmt = va_arg (ap, const char *);
375 #endif
376
377   if (CPU_DEBUG_FILE (cpu) == NULL)
378     (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
379       (STATE_CALLBACK (CPU_STATE (cpu)), fmt, ap);
380   else
381     vfprintf (CPU_DEBUG_FILE (cpu), fmt, ap);
382
383   va_end (ap);
384 }