replaced call to CGEN_INSN_SYNTAX()->mnemonic with CGEN_INSN_MNEMONIC()
[external/binutils.git] / sim / common / cgen-trace.c
1 /* Tracing support for CGEN-based simulators.
2    Copyright (C) 1996, 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 "bfd.h"
23 #include "cpu-opc.h"
24
25 #ifndef SIZE_INSTRUCTION
26 #define SIZE_INSTRUCTION 16
27 #endif
28
29 #ifndef SIZE_LOCATION
30 #define SIZE_LOCATION 20
31 #endif
32
33 #ifndef SIZE_PC
34 #define SIZE_PC 6
35 #endif
36
37 #ifndef SIZE_LINE_NUMBER
38 #define SIZE_LINE_NUMBER 4
39 #endif
40
41 #ifndef SIZE_CYCLE_COUNT
42 #define SIZE_CYCLE_COUNT 2
43 #endif
44
45 #ifndef SIZE_TOTAL_CYCLE_COUNT
46 #define SIZE_TOTAL_CYCLE_COUNT 9
47 #endif
48
49 /* Text is queued in TRACE_BUF because we want to output the insn's cycle
50    count first but that isn't known until after the insn has executed.  */
51 static char trace_buf[1024];
52 /* If NULL, output to stdout directly.  */
53 static char *bufptr;
54
55 /* For computing an instruction's cycle count.
56    FIXME: Need to move into cpu struct for smp case.  */
57 static unsigned long last_cycle_count;
58
59 void
60 trace_insn_init (SIM_CPU *cpu)
61 {
62   bufptr = trace_buf;
63   *bufptr = 0;
64 }
65
66 void
67 trace_insn_fini (SIM_CPU *cpu)
68 {
69   if (CPU_PROFILE_FLAGS (cpu) [PROFILE_MODEL_IDX])
70     {
71       unsigned long total = PROFILE_TOTAL_CYCLE_COUNT (CPU_PROFILE_DATA (cpu));
72       trace_printf (CPU_STATE (cpu), cpu, "%-*ld %-*ld ",
73                     SIZE_CYCLE_COUNT, total - last_cycle_count,
74                     SIZE_TOTAL_CYCLE_COUNT, total);
75       last_cycle_count = total;
76     }
77
78   trace_printf (CPU_STATE (cpu), cpu, "%s\n", trace_buf);
79 }
80
81 /* For communication between trace_insn and trace_result.  */
82 static int printed_result_p;
83
84 void
85 trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
86             const struct argbuf *abuf, PCADDR pc)
87 {
88   const char *filename;
89   const char *functionname;
90   unsigned int linenumber;
91   char *p, buf[256], disasm_buf[50];
92
93   if (! TRACE_P (cpu, TRACE_LINENUM_IDX))
94     {
95       cgen_trace_printf (cpu, "0x%.*x %-*s ",
96                          SIZE_PC, (unsigned) pc,
97                          SIZE_INSTRUCTION,
98                          CGEN_INSN_MNEMONIC (opcode));
99       return;
100     }
101
102   buf[0] = 0;
103   
104   if (STATE_TEXT_SECTION (CPU_STATE (cpu))
105       && pc >= STATE_TEXT_START (CPU_STATE (cpu))
106       && pc < STATE_TEXT_END (CPU_STATE (cpu)))
107     {
108       filename = (const char *) 0;
109       functionname = (const char *) 0;
110       linenumber = 0;
111       if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)),
112                                  STATE_TEXT_SECTION (CPU_STATE (cpu)),
113                                  (struct symbol_cache_entry **) 0,
114                                  pc - STATE_TEXT_START (CPU_STATE (cpu)),
115                                  &filename, &functionname, &linenumber))
116         {
117           p = buf;
118           if (linenumber)
119             {
120               sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, linenumber);
121               p += strlen (p);
122             }
123           else
124             {
125               sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---");
126               p += SIZE_LINE_NUMBER+2;
127             }
128
129           if (functionname)
130             {
131               sprintf (p, "%s ", functionname);
132               p += strlen (p);
133             }
134           else if (filename)
135             {
136               char *q = (char *) strrchr (filename, '/');
137               sprintf (p, "%s ", (q) ? q+1 : filename);
138               p += strlen (p);
139             }
140
141           if (*p == ' ')
142             *p = '\0';
143         }
144     }
145
146   sim_disassemble_insn (cpu, opcode, abuf, pc, disasm_buf);
147
148   cgen_trace_printf (cpu, "0x%.*x %-*.*s %-*s ",
149                      SIZE_PC, (unsigned) pc,
150                      SIZE_LOCATION, SIZE_LOCATION, buf,
151                      SIZE_INSTRUCTION,
152 #if 0
153                      CGEN_INSN_SYNTAX (opcode)->mnemonic
154 #else
155                      disasm_buf
156 #endif
157                 );
158
159   printed_result_p = 0;
160 }
161
162 void
163 trace_extract (SIM_CPU *cpu, PCADDR pc, char *name, ...)
164 {
165   va_list args;
166   int printed_one_p = 0;
167   char *fmt;
168
169   va_start (args, name);
170
171   trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*x: %s ", SIZE_PC, pc, name);
172
173   do {
174     int type,ival;
175
176     fmt = va_arg (args, char *);
177
178     if (fmt)
179       {
180         if (printed_one_p)
181           trace_printf (CPU_STATE (cpu), cpu, ", ");
182         printed_one_p = 1;
183         type = va_arg (args, int);
184         switch (type)
185           {
186           case 'x' :
187             ival = va_arg (args, int);
188             trace_printf (CPU_STATE (cpu), cpu, fmt, ival);
189             break;
190           default :
191             abort ();
192           }
193       }
194   } while (fmt);
195
196   va_end (args);
197   trace_printf (CPU_STATE (cpu), cpu, "\n");
198 }
199
200 void
201 trace_result (SIM_CPU *cpu, char *name, int type, ...)
202 {
203   va_list args;
204
205   va_start (args, type);
206   if (printed_result_p)
207     cgen_trace_printf (cpu, ", ");
208   switch (type)
209     {
210     case 'x' :
211     default :
212       cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int));
213       break;
214     case 'D' :
215       {
216         DI di;
217         /* this is separated from previous line for sunos cc */
218         di = va_arg (args, DI);
219         cgen_trace_printf (cpu, "%s <- 0x%x%08x", name,
220                            GETHIDI(di), GETLODI (di));
221         break;
222       }
223     }
224   printed_result_p = 1;
225   va_end (args);
226 }
227
228 /* Print trace output to BUFPTR if active, otherwise print normally.
229    This is only for tracing semantic code.  */
230
231 void
232 cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...)
233 {
234   va_list args;
235
236   va_start (args, fmt);
237
238   if (bufptr == NULL)
239     {
240       if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL)
241         (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
242           (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args);
243       else
244         vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args);
245     }
246   else
247     {
248       vsprintf (bufptr, fmt, args);
249       bufptr += strlen (bufptr);
250     }
251
252   va_end (args);
253 }