trace.c revision 1.11 1 1.1 christos /* trace.c --- tracing output for the RX simulator.
2 1.1 christos
3 1.11 christos Copyright (C) 2005-2024 Free Software Foundation, Inc.
4 1.1 christos Contributed by Red Hat, Inc.
5 1.1 christos
6 1.1 christos This file is part of the GNU simulators.
7 1.1 christos
8 1.1 christos This program is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3 of the License, or
11 1.1 christos (at your option) any later version.
12 1.1 christos
13 1.1 christos This program is distributed in the hope that it will be useful,
14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 christos GNU General Public License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 1.1 christos
21 1.10 christos /* This must come before any other includes. */
22 1.10 christos #include "defs.h"
23 1.1 christos
24 1.1 christos #include <stdio.h>
25 1.1 christos #include <stdarg.h>
26 1.1 christos #include <string.h>
27 1.1 christos #include <stdlib.h>
28 1.1 christos #include <sys/types.h>
29 1.1 christos #include <sys/stat.h>
30 1.1 christos #include <ctype.h>
31 1.1 christos
32 1.1 christos #include "bfd.h"
33 1.1 christos #include "dis-asm.h"
34 1.1 christos
35 1.1 christos #include "cpu.h"
36 1.1 christos #include "mem.h"
37 1.1 christos #include "load.h"
38 1.10 christos #include "trace.h"
39 1.1 christos
40 1.1 christos static int
41 1.1 christos sim_dis_read (bfd_vma memaddr, bfd_byte * ptr, unsigned int length,
42 1.1 christos struct disassemble_info *info)
43 1.1 christos {
44 1.1 christos int i;
45 1.1 christos
46 1.1 christos if (rx_big_endian)
47 1.1 christos {
48 1.1 christos /* See load.c for an explanation of this. */
49 1.1 christos for (i=0; i<length; i++)
50 1.1 christos ptr[i] = mem_get_qi ((memaddr + i) ^ 3);
51 1.1 christos }
52 1.1 christos else
53 1.1 christos mem_get_blk (memaddr, ptr, length);
54 1.1 christos return 0;
55 1.1 christos }
56 1.1 christos
57 1.1 christos /* Filter out (in place) symbols that are useless for disassembly.
58 1.1 christos COUNT is the number of elements in SYMBOLS.
59 1.1 christos Return the number of useful symbols. */
60 1.1 christos
61 1.1 christos static long
62 1.1 christos remove_useless_symbols (asymbol ** symbols, long count)
63 1.1 christos {
64 1.1 christos register asymbol **in_ptr = symbols, **out_ptr = symbols;
65 1.1 christos
66 1.1 christos while (--count >= 0)
67 1.1 christos {
68 1.1 christos asymbol *sym = *in_ptr++;
69 1.1 christos
70 1.1 christos if (strstr (sym->name, "gcc2_compiled"))
71 1.1 christos continue;
72 1.1 christos if (sym->name == NULL || sym->name[0] == '\0')
73 1.1 christos continue;
74 1.1 christos if (sym->flags & (BSF_DEBUGGING))
75 1.1 christos continue;
76 1.1 christos if (bfd_is_und_section (sym->section)
77 1.1 christos || bfd_is_com_section (sym->section))
78 1.1 christos continue;
79 1.1 christos
80 1.1 christos *out_ptr++ = sym;
81 1.1 christos }
82 1.1 christos return out_ptr - symbols;
83 1.1 christos }
84 1.1 christos
85 1.1 christos static int
86 1.10 christos compare_symbols (const void *ap, const void *bp)
87 1.1 christos {
88 1.1 christos const asymbol *a = *(const asymbol **) ap;
89 1.1 christos const asymbol *b = *(const asymbol **) bp;
90 1.1 christos
91 1.1 christos if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
92 1.1 christos return 1;
93 1.1 christos else if (bfd_asymbol_value (a) < bfd_asymbol_value (b))
94 1.1 christos return -1;
95 1.1 christos return 0;
96 1.1 christos }
97 1.1 christos
98 1.1 christos static char opbuf[1000];
99 1.1 christos
100 1.10 christos static int ATTRIBUTE_PRINTF (2, 3)
101 1.1 christos op_printf (char *buf, char *fmt, ...)
102 1.1 christos {
103 1.1 christos int ret;
104 1.1 christos va_list ap;
105 1.1 christos
106 1.1 christos va_start (ap, fmt);
107 1.1 christos ret = vsprintf (opbuf + strlen (opbuf), fmt, ap);
108 1.1 christos va_end (ap);
109 1.1 christos return ret;
110 1.1 christos }
111 1.1 christos
112 1.10 christos static int ATTRIBUTE_PRINTF (3, 4)
113 1.10 christos op_styled_printf (char *buf, enum disassembler_style style, char *fmt, ...)
114 1.10 christos {
115 1.10 christos int ret;
116 1.10 christos va_list ap;
117 1.10 christos
118 1.10 christos va_start (ap, fmt);
119 1.10 christos ret = vsprintf (opbuf + strlen (opbuf), fmt, ap);
120 1.10 christos va_end (ap);
121 1.10 christos return ret;
122 1.10 christos }
123 1.10 christos
124 1.1 christos static bfd * current_bfd = NULL;
125 1.1 christos static asymbol ** symtab = NULL;
126 1.1 christos static int symcount = 0;
127 1.1 christos static asection * code_section = NULL;
128 1.1 christos static bfd_vma code_base = 0;
129 1.1 christos static struct disassemble_info info;
130 1.1 christos
131 1.1 christos void
132 1.1 christos sim_disasm_init (bfd *prog)
133 1.1 christos {
134 1.1 christos current_bfd = prog;
135 1.1 christos }
136 1.1 christos
137 1.1 christos typedef struct Files
138 1.1 christos {
139 1.1 christos struct Files *next;
140 1.1 christos char *filename;
141 1.1 christos int nlines;
142 1.1 christos char **lines;
143 1.1 christos char *data;
144 1.1 christos } Files;
145 1.1 christos Files *files = 0;
146 1.1 christos
147 1.1 christos static char *
148 1.1 christos load_file_and_line (const char *filename, int lineno)
149 1.1 christos {
150 1.1 christos Files *f;
151 1.1 christos for (f = files; f; f = f->next)
152 1.1 christos if (strcmp (f->filename, filename) == 0)
153 1.1 christos break;
154 1.1 christos if (!f)
155 1.1 christos {
156 1.10 christos FILE *file;
157 1.1 christos int i;
158 1.1 christos struct stat s;
159 1.10 christos size_t ret;
160 1.1 christos const char *found_filename, *slash;
161 1.1 christos
162 1.1 christos found_filename = filename;
163 1.1 christos while (1)
164 1.1 christos {
165 1.1 christos if (stat (found_filename, &s) == 0)
166 1.1 christos break;
167 1.1 christos slash = strchr (found_filename, '/');
168 1.1 christos if (!slash)
169 1.1 christos return "";
170 1.1 christos found_filename = slash + 1;
171 1.1 christos }
172 1.1 christos
173 1.1 christos f = (Files *) malloc (sizeof (Files));
174 1.1 christos f->next = files;
175 1.1 christos files = f;
176 1.1 christos f->filename = strdup (filename);
177 1.1 christos f->data = (char *) malloc (s.st_size + 2);
178 1.10 christos file = fopen (found_filename, "rb");
179 1.10 christos ret = fread (f->data, 1, s.st_size, file);
180 1.10 christos f->data[ret] = 0;
181 1.1 christos fclose (file);
182 1.1 christos
183 1.1 christos f->nlines = 1;
184 1.1 christos for (i = 0; i < s.st_size; i++)
185 1.1 christos if (f->data[i] == '\n')
186 1.1 christos f->nlines++;
187 1.1 christos f->lines = (char **) malloc (f->nlines * sizeof (char *));
188 1.1 christos f->lines[0] = f->data;
189 1.1 christos f->nlines = 1;
190 1.1 christos for (i = 0; i < s.st_size; i++)
191 1.1 christos if (f->data[i] == '\n')
192 1.1 christos {
193 1.1 christos f->lines[f->nlines] = f->data + i + 1;
194 1.1 christos while (*f->lines[f->nlines] == ' '
195 1.1 christos || *f->lines[f->nlines] == '\t')
196 1.1 christos f->lines[f->nlines]++;
197 1.1 christos f->nlines++;
198 1.1 christos f->data[i] = 0;
199 1.1 christos }
200 1.1 christos }
201 1.1 christos if (lineno < 1 || lineno > f->nlines)
202 1.1 christos return "";
203 1.1 christos return f->lines[lineno - 1];
204 1.1 christos }
205 1.1 christos
206 1.1 christos int
207 1.1 christos sim_get_current_source_location (const char ** pfilename,
208 1.1 christos const char ** pfunctionname,
209 1.1 christos unsigned int * plineno)
210 1.1 christos {
211 1.1 christos static int initted = 0;
212 1.1 christos int mypc = get_reg (pc);
213 1.1 christos
214 1.1 christos if (current_bfd == NULL)
215 1.1 christos return 0;
216 1.1 christos
217 1.1 christos if (!initted)
218 1.1 christos {
219 1.1 christos int storage;
220 1.1 christos asection * s;
221 1.1 christos
222 1.1 christos initted = 1;
223 1.1 christos memset (& info, 0, sizeof (info));
224 1.10 christos INIT_DISASSEMBLE_INFO (info, stdout, op_printf, op_styled_printf);
225 1.1 christos info.read_memory_func = sim_dis_read;
226 1.1 christos info.arch = bfd_get_arch (current_bfd);
227 1.1 christos info.mach = bfd_get_mach (current_bfd);
228 1.1 christos if (info.mach == 0)
229 1.1 christos info.arch = bfd_arch_rx;
230 1.1 christos
231 1.1 christos disassemble_init_for_target (& info);
232 1.1 christos
233 1.1 christos storage = bfd_get_symtab_upper_bound (current_bfd);
234 1.1 christos if (storage > 0)
235 1.1 christos {
236 1.1 christos symtab = (asymbol **) malloc (storage);
237 1.1 christos symcount = bfd_canonicalize_symtab (current_bfd, symtab);
238 1.1 christos symcount = remove_useless_symbols (symtab, symcount);
239 1.1 christos qsort (symtab, symcount, sizeof (asymbol *), compare_symbols);
240 1.1 christos }
241 1.1 christos
242 1.1 christos for (s = current_bfd->sections; s; s = s->next)
243 1.1 christos {
244 1.1 christos if (s->flags & SEC_CODE || code_section == 0)
245 1.1 christos {
246 1.1 christos code_section = s;
247 1.9 christos code_base = bfd_section_lma (s);
248 1.1 christos break;
249 1.1 christos }
250 1.1 christos }
251 1.1 christos }
252 1.1 christos
253 1.1 christos *pfilename = *pfunctionname = NULL;
254 1.1 christos *plineno = 0;
255 1.1 christos
256 1.1 christos bfd_find_nearest_line
257 1.1 christos (current_bfd, code_section, symtab, mypc - code_base,
258 1.1 christos pfilename, pfunctionname, plineno);
259 1.1 christos
260 1.1 christos return 1;
261 1.1 christos }
262 1.1 christos
263 1.1 christos void
264 1.1 christos sim_disasm_one (void)
265 1.1 christos {
266 1.1 christos static int last_sym = -1;
267 1.1 christos static const char * prev_filename = "";
268 1.1 christos static int prev_lineno = 0;
269 1.1 christos const char * filename;
270 1.1 christos const char * functionname;
271 1.1 christos unsigned int lineno;
272 1.1 christos int sym, bestaddr;
273 1.1 christos int min, max, i;
274 1.1 christos int save_trace = trace;
275 1.1 christos int mypc = get_reg (pc);
276 1.1 christos
277 1.1 christos if (! sim_get_current_source_location (& filename, & functionname, & lineno))
278 1.1 christos return;
279 1.1 christos
280 1.1 christos trace = 0;
281 1.1 christos
282 1.1 christos if (filename && functionname && lineno)
283 1.1 christos {
284 1.1 christos if (lineno != prev_lineno || strcmp (prev_filename, filename))
285 1.1 christos {
286 1.1 christos char * the_line = load_file_and_line (filename, lineno);
287 1.1 christos const char * slash = strrchr (filename, '/');
288 1.1 christos
289 1.1 christos if (!slash)
290 1.1 christos slash = filename;
291 1.1 christos else
292 1.1 christos slash++;
293 1.1 christos printf
294 1.1 christos ("========================================"
295 1.1 christos "=====================================\n");
296 1.1 christos printf ("\033[37;41m %s:%d: \033[33;40m %s\033[K\033[0m\n",
297 1.1 christos slash, lineno, the_line);
298 1.1 christos }
299 1.1 christos prev_lineno = lineno;
300 1.1 christos prev_filename = filename;
301 1.1 christos }
302 1.1 christos
303 1.1 christos min = -1;
304 1.1 christos max = symcount;
305 1.1 christos while (min < max - 1)
306 1.1 christos {
307 1.1 christos bfd_vma sa;
308 1.1 christos
309 1.1 christos sym = (min + max) / 2;
310 1.1 christos sa = bfd_asymbol_value (symtab[sym]);
311 1.1 christos /*printf("checking %4d %08x %s\n",
312 1.1 christos sym, sa, bfd_asymbol_name (symtab[sym])); */
313 1.1 christos if (sa > mypc)
314 1.1 christos max = sym;
315 1.1 christos else if (sa < mypc)
316 1.1 christos min = sym;
317 1.1 christos else
318 1.1 christos {
319 1.1 christos min = sym;
320 1.1 christos break;
321 1.1 christos }
322 1.1 christos }
323 1.1 christos
324 1.1 christos if (min != -1 && min != last_sym)
325 1.1 christos {
326 1.1 christos bestaddr = bfd_asymbol_value (symtab[min]);
327 1.1 christos printf ("\033[43;30m%s", bfd_asymbol_name (symtab[min]));
328 1.1 christos if (bestaddr != mypc)
329 1.1 christos printf ("+%d", mypc - bestaddr);
330 1.1 christos printf (":\t\t\t\033[0m\n");
331 1.1 christos last_sym = min;
332 1.1 christos #if 0
333 1.1 christos if (trace == 1)
334 1.1 christos if (strcmp (bfd_asymbol_name (symtab[min]), "abort") == 0
335 1.1 christos || strcmp (bfd_asymbol_name (symtab[min]), "exit") == 0)
336 1.1 christos trace = 0;
337 1.1 christos #endif
338 1.1 christos }
339 1.1 christos
340 1.1 christos opbuf[0] = 0;
341 1.1 christos #ifdef CYCLE_ACCURATE
342 1.1 christos printf ("\033[33m %04u %06x: ", (int)(regs.cycle_count % 10000), mypc);
343 1.1 christos #else
344 1.1 christos printf ("\033[33m %06x: ", mypc);
345 1.1 christos
346 1.1 christos #endif
347 1.1 christos
348 1.1 christos max = print_insn_rx (mypc, & info);
349 1.1 christos
350 1.1 christos for (i = 0; i < max; i++)
351 1.1 christos {
352 1.1 christos if (rx_big_endian)
353 1.1 christos printf ("%02x", mem_get_qi ((mypc + i) ^ 3));
354 1.1 christos else
355 1.1 christos printf ("%02x", mem_get_qi (mypc + i));
356 1.1 christos }
357 1.1 christos
358 1.1 christos do
359 1.1 christos {
360 1.1 christos printf (" ");
361 1.1 christos i ++;
362 1.1 christos }
363 1.1 christos while (i < 6);
364 1.1 christos
365 1.1 christos printf ("%-16s ", opbuf);
366 1.1 christos
367 1.1 christos printf ("\033[0m\n");
368 1.1 christos trace = save_trace;
369 1.1 christos }
370