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