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