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