Commit | Line | Data |
---|---|---|
b9c8cd10 DE |
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 know 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 | fprintf (stderr, "%-*ld %-*ld ", | |
73 | SIZE_CYCLE_COUNT, total - last_cycle_count, | |
74 | SIZE_TOTAL_CYCLE_COUNT, total); | |
75 | last_cycle_count = total; | |
76 | } | |
77 | ||
78 | fputs (trace_buf, stderr); | |
79 | fputc ('\n', stderr); | |
80 | } | |
81 | ||
82 | /* For communication between trace_insn and trace_result. */ | |
83 | static int printed_result_p; | |
84 | ||
85 | void | |
86 | trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode, | |
87 | const struct argbuf *abuf, PCADDR pc) | |
88 | { | |
89 | const char *filename; | |
90 | const char *functionname; | |
91 | unsigned int linenumber; | |
92 | char *p, buf[256], disasm_buf[50]; | |
93 | ||
94 | if (! TRACE_P (cpu, TRACE_LINENUM_IDX)) | |
95 | { | |
96 | cgen_trace_printf (cpu, "0x%.*x %-*s ", | |
97 | SIZE_PC, (unsigned) pc, | |
98 | SIZE_INSTRUCTION, | |
99 | CGEN_INSN_SYNTAX (opcode)->mnemonic); | |
100 | return; | |
101 | } | |
102 | ||
103 | buf[0] = 0; | |
104 | ||
105 | if (STATE_TEXT_SECTION (CPU_STATE (cpu)) | |
106 | && pc >= STATE_TEXT_START (CPU_STATE (cpu)) | |
107 | && pc < STATE_TEXT_END (CPU_STATE (cpu))) | |
108 | { | |
109 | filename = (const char *) 0; | |
110 | functionname = (const char *) 0; | |
111 | linenumber = 0; | |
112 | if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)), | |
113 | STATE_TEXT_SECTION (CPU_STATE (cpu)), | |
114 | (struct symbol_cache_entry **) 0, | |
115 | pc - STATE_TEXT_START (CPU_STATE (cpu)), | |
116 | &filename, &functionname, &linenumber)) | |
117 | { | |
118 | p = buf; | |
119 | if (linenumber) | |
120 | { | |
121 | sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, linenumber); | |
122 | p += strlen (p); | |
123 | } | |
124 | else | |
125 | { | |
126 | sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---"); | |
127 | p += SIZE_LINE_NUMBER+2; | |
128 | } | |
129 | ||
130 | if (functionname) | |
131 | { | |
132 | sprintf (p, "%s ", functionname); | |
133 | p += strlen (p); | |
134 | } | |
135 | else if (filename) | |
136 | { | |
137 | char *q = (char *) strrchr (filename, '/'); | |
138 | sprintf (p, "%s ", (q) ? q+1 : filename); | |
139 | p += strlen (p); | |
140 | } | |
141 | ||
142 | if (*p == ' ') | |
143 | *p = '\0'; | |
144 | } | |
145 | } | |
146 | ||
147 | sim_disassemble_insn (opcode, abuf, pc, disasm_buf); | |
148 | ||
149 | cgen_trace_printf (cpu, "0x%.*x %-*.*s %-*s ", | |
150 | SIZE_PC, (unsigned) pc, | |
151 | SIZE_LOCATION, SIZE_LOCATION, buf, | |
152 | SIZE_INSTRUCTION, | |
153 | #if 0 | |
154 | CGEN_INSN_SYNTAX (opcode)->mnemonic | |
155 | #else | |
156 | disasm_buf | |
157 | #endif | |
158 | ); | |
159 | ||
160 | printed_result_p = 0; | |
161 | } | |
162 | ||
163 | void | |
164 | trace_extract (SIM_CPU *cpu, PCADDR pc, char *name, ...) | |
165 | { | |
166 | va_list args; | |
167 | int printed_one_p = 0; | |
168 | char *fmt; | |
169 | ||
170 | va_start (args, name); | |
171 | ||
172 | cgen_trace_printf (cpu, "0x%.*x: %s ", SIZE_PC, pc, name); | |
173 | ||
174 | do { | |
175 | int type,ival; | |
176 | ||
177 | fmt = va_arg (args, char *); | |
178 | ||
179 | if (fmt) | |
180 | { | |
181 | if (printed_one_p) | |
182 | cgen_trace_printf (cpu, ", "); | |
183 | printed_one_p = 1; | |
184 | type = va_arg (args, int); | |
185 | switch (type) | |
186 | { | |
187 | case 'x' : | |
188 | ival = va_arg (args, int); | |
189 | cgen_trace_printf (cpu, fmt, ival); | |
190 | break; | |
191 | default : | |
192 | abort (); | |
193 | } | |
194 | } | |
195 | } while (fmt); | |
196 | ||
197 | va_end (args); | |
198 | cgen_trace_printf (cpu, "\n"); | |
199 | } | |
200 | ||
201 | void | |
202 | trace_result (SIM_CPU *cpu, char *name, int type, ...) | |
203 | { | |
204 | va_list args; | |
205 | ||
206 | va_start (args, type); | |
207 | if (printed_result_p) | |
208 | cgen_trace_printf (cpu, ", "); | |
209 | switch (type) | |
210 | { | |
211 | case 'x' : | |
212 | default : | |
213 | cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int)); | |
214 | break; | |
215 | case 'D' : | |
216 | { | |
217 | DI di; | |
218 | /* this is separated from previous line for sunos cc */ | |
219 | di = va_arg (args, DI); | |
220 | cgen_trace_printf (cpu, "%s <- 0x%x%08x", name, | |
221 | GETHIDI(di), GETLODI (di)); | |
222 | break; | |
223 | } | |
224 | } | |
225 | printed_result_p = 1; | |
226 | va_end (args); | |
227 | } | |
228 | ||
229 | void | |
230 | cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...) | |
231 | { | |
232 | va_list args; | |
233 | ||
234 | va_start (args, fmt); | |
235 | ||
236 | if (bufptr == NULL) | |
237 | { | |
238 | if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL) | |
239 | (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered) | |
240 | (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args); | |
241 | else | |
242 | vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args); | |
243 | } | |
244 | else | |
245 | { | |
246 | vsprintf (bufptr, fmt, args); | |
247 | bufptr += strlen (bufptr); | |
248 | } | |
249 | ||
250 | va_end (args); | |
251 | } |