xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/trace.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
14e98e3e1Schristos /* trace.c --- tracing output for the RX simulator.
24e98e3e1Schristos 
3*1f4e7eb9Schristos Copyright (C) 2005-2024 Free Software Foundation, Inc.
44e98e3e1Schristos Contributed by Red Hat, Inc.
54e98e3e1Schristos 
64e98e3e1Schristos This file is part of the GNU simulators.
74e98e3e1Schristos 
84e98e3e1Schristos This program is free software; you can redistribute it and/or modify
94e98e3e1Schristos it under the terms of the GNU General Public License as published by
104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
114e98e3e1Schristos (at your option) any later version.
124e98e3e1Schristos 
134e98e3e1Schristos This program is distributed in the hope that it will be useful,
144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164e98e3e1Schristos GNU General Public License for more details.
174e98e3e1Schristos 
184e98e3e1Schristos You should have received a copy of the GNU General Public License
194e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
204e98e3e1Schristos 
214b169a6bSchristos /* This must come before any other includes.  */
224b169a6bSchristos #include "defs.h"
234e98e3e1Schristos 
244e98e3e1Schristos #include <stdio.h>
254e98e3e1Schristos #include <stdarg.h>
264e98e3e1Schristos #include <string.h>
274e98e3e1Schristos #include <stdlib.h>
284e98e3e1Schristos #include <sys/types.h>
294e98e3e1Schristos #include <sys/stat.h>
304e98e3e1Schristos #include <ctype.h>
314e98e3e1Schristos 
324e98e3e1Schristos #include "bfd.h"
334e98e3e1Schristos #include "dis-asm.h"
344e98e3e1Schristos 
354e98e3e1Schristos #include "cpu.h"
364e98e3e1Schristos #include "mem.h"
374e98e3e1Schristos #include "load.h"
384b169a6bSchristos #include "trace.h"
394e98e3e1Schristos 
404e98e3e1Schristos static int
414e98e3e1Schristos sim_dis_read (bfd_vma memaddr, bfd_byte * ptr, unsigned int length,
424e98e3e1Schristos 	      struct disassemble_info *info)
434e98e3e1Schristos {
444e98e3e1Schristos   int i;
454e98e3e1Schristos 
464e98e3e1Schristos   if (rx_big_endian)
474e98e3e1Schristos     {
484e98e3e1Schristos       /* See load.c for an explanation of this.  */
494e98e3e1Schristos       for (i=0; i<length; i++)
504e98e3e1Schristos 	ptr[i] = mem_get_qi ((memaddr + i) ^ 3);
514e98e3e1Schristos     }
524e98e3e1Schristos   else
534e98e3e1Schristos     mem_get_blk (memaddr, ptr, length);
544e98e3e1Schristos   return 0;
554e98e3e1Schristos }
564e98e3e1Schristos 
574e98e3e1Schristos /* Filter out (in place) symbols that are useless for disassembly.
584e98e3e1Schristos    COUNT is the number of elements in SYMBOLS.
594e98e3e1Schristos    Return the number of useful symbols. */
604e98e3e1Schristos 
614e98e3e1Schristos static long
624e98e3e1Schristos remove_useless_symbols (asymbol ** symbols, long count)
634e98e3e1Schristos {
644e98e3e1Schristos   register asymbol **in_ptr = symbols, **out_ptr = symbols;
654e98e3e1Schristos 
664e98e3e1Schristos   while (--count >= 0)
674e98e3e1Schristos     {
684e98e3e1Schristos       asymbol *sym = *in_ptr++;
694e98e3e1Schristos 
704e98e3e1Schristos       if (strstr (sym->name, "gcc2_compiled"))
714e98e3e1Schristos 	continue;
724e98e3e1Schristos       if (sym->name == NULL || sym->name[0] == '\0')
734e98e3e1Schristos 	continue;
744e98e3e1Schristos       if (sym->flags & (BSF_DEBUGGING))
754e98e3e1Schristos 	continue;
764e98e3e1Schristos       if (bfd_is_und_section (sym->section)
774e98e3e1Schristos 	  || bfd_is_com_section (sym->section))
784e98e3e1Schristos 	continue;
794e98e3e1Schristos 
804e98e3e1Schristos       *out_ptr++ = sym;
814e98e3e1Schristos     }
824e98e3e1Schristos   return out_ptr - symbols;
834e98e3e1Schristos }
844e98e3e1Schristos 
854e98e3e1Schristos static int
864b169a6bSchristos compare_symbols (const void *ap, const void *bp)
874e98e3e1Schristos {
884e98e3e1Schristos   const asymbol *a = *(const asymbol **) ap;
894e98e3e1Schristos   const asymbol *b = *(const asymbol **) bp;
904e98e3e1Schristos 
914e98e3e1Schristos   if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
924e98e3e1Schristos     return 1;
934e98e3e1Schristos   else if (bfd_asymbol_value (a) < bfd_asymbol_value (b))
944e98e3e1Schristos     return -1;
954e98e3e1Schristos   return 0;
964e98e3e1Schristos }
974e98e3e1Schristos 
984e98e3e1Schristos static char opbuf[1000];
994e98e3e1Schristos 
1004b169a6bSchristos static int ATTRIBUTE_PRINTF (2, 3)
1014e98e3e1Schristos op_printf (char *buf, char *fmt, ...)
1024e98e3e1Schristos {
1034e98e3e1Schristos   int ret;
1044e98e3e1Schristos   va_list ap;
1054e98e3e1Schristos 
1064e98e3e1Schristos   va_start (ap, fmt);
1074e98e3e1Schristos   ret = vsprintf (opbuf + strlen (opbuf), fmt, ap);
1084e98e3e1Schristos   va_end (ap);
1094e98e3e1Schristos   return ret;
1104e98e3e1Schristos }
1114e98e3e1Schristos 
1124b169a6bSchristos static int ATTRIBUTE_PRINTF (3, 4)
1134b169a6bSchristos op_styled_printf (char *buf, enum disassembler_style style, char *fmt, ...)
1144b169a6bSchristos {
1154b169a6bSchristos   int ret;
1164b169a6bSchristos   va_list ap;
1174b169a6bSchristos 
1184b169a6bSchristos   va_start (ap, fmt);
1194b169a6bSchristos   ret = vsprintf (opbuf + strlen (opbuf), fmt, ap);
1204b169a6bSchristos   va_end (ap);
1214b169a6bSchristos   return ret;
1224b169a6bSchristos }
1234b169a6bSchristos 
1244e98e3e1Schristos static bfd *       current_bfd = NULL;
1254e98e3e1Schristos static asymbol **  symtab = NULL;
1264e98e3e1Schristos static int         symcount = 0;
1274e98e3e1Schristos static asection *  code_section = NULL;
1284e98e3e1Schristos static bfd_vma     code_base = 0;
1294e98e3e1Schristos static struct disassemble_info info;
1304e98e3e1Schristos 
1314e98e3e1Schristos void
1324e98e3e1Schristos sim_disasm_init (bfd *prog)
1334e98e3e1Schristos {
1344e98e3e1Schristos   current_bfd = prog;
1354e98e3e1Schristos }
1364e98e3e1Schristos 
1374e98e3e1Schristos typedef struct Files
1384e98e3e1Schristos {
1394e98e3e1Schristos   struct Files *next;
1404e98e3e1Schristos   char *filename;
1414e98e3e1Schristos   int nlines;
1424e98e3e1Schristos   char **lines;
1434e98e3e1Schristos   char *data;
1444e98e3e1Schristos } Files;
1454e98e3e1Schristos Files *files = 0;
1464e98e3e1Schristos 
1474e98e3e1Schristos static char *
1484e98e3e1Schristos load_file_and_line (const char *filename, int lineno)
1494e98e3e1Schristos {
1504e98e3e1Schristos   Files *f;
1514e98e3e1Schristos   for (f = files; f; f = f->next)
1524e98e3e1Schristos     if (strcmp (f->filename, filename) == 0)
1534e98e3e1Schristos       break;
1544e98e3e1Schristos   if (!f)
1554e98e3e1Schristos     {
1564b169a6bSchristos       FILE *file;
1574e98e3e1Schristos       int i;
1584e98e3e1Schristos       struct stat s;
1594b169a6bSchristos       size_t ret;
1604e98e3e1Schristos       const char *found_filename, *slash;
1614e98e3e1Schristos 
1624e98e3e1Schristos       found_filename = filename;
1634e98e3e1Schristos       while (1)
1644e98e3e1Schristos 	{
1654e98e3e1Schristos 	  if (stat (found_filename, &s) == 0)
1664e98e3e1Schristos 	    break;
1674e98e3e1Schristos 	  slash = strchr (found_filename, '/');
1684e98e3e1Schristos 	  if (!slash)
1694e98e3e1Schristos 	    return "";
1704e98e3e1Schristos 	  found_filename = slash + 1;
1714e98e3e1Schristos 	}
1724e98e3e1Schristos 
1734e98e3e1Schristos       f = (Files *) malloc (sizeof (Files));
1744e98e3e1Schristos       f->next = files;
1754e98e3e1Schristos       files = f;
1764e98e3e1Schristos       f->filename = strdup (filename);
1774e98e3e1Schristos       f->data = (char *) malloc (s.st_size + 2);
1784b169a6bSchristos       file = fopen (found_filename, "rb");
1794b169a6bSchristos       ret = fread (f->data, 1, s.st_size, file);
1804b169a6bSchristos       f->data[ret] = 0;
1814e98e3e1Schristos       fclose (file);
1824e98e3e1Schristos 
1834e98e3e1Schristos       f->nlines = 1;
1844e98e3e1Schristos       for (i = 0; i < s.st_size; i++)
1854e98e3e1Schristos 	if (f->data[i] == '\n')
1864e98e3e1Schristos 	  f->nlines++;
1874e98e3e1Schristos       f->lines = (char **) malloc (f->nlines * sizeof (char *));
1884e98e3e1Schristos       f->lines[0] = f->data;
1894e98e3e1Schristos       f->nlines = 1;
1904e98e3e1Schristos       for (i = 0; i < s.st_size; i++)
1914e98e3e1Schristos 	if (f->data[i] == '\n')
1924e98e3e1Schristos 	  {
1934e98e3e1Schristos 	    f->lines[f->nlines] = f->data + i + 1;
1944e98e3e1Schristos 	    while (*f->lines[f->nlines] == ' '
1954e98e3e1Schristos 		   || *f->lines[f->nlines] == '\t')
1964e98e3e1Schristos 	      f->lines[f->nlines]++;
1974e98e3e1Schristos 	    f->nlines++;
1984e98e3e1Schristos 	    f->data[i] = 0;
1994e98e3e1Schristos 	  }
2004e98e3e1Schristos     }
2014e98e3e1Schristos   if (lineno < 1 || lineno > f->nlines)
2024e98e3e1Schristos     return "";
2034e98e3e1Schristos   return f->lines[lineno - 1];
2044e98e3e1Schristos }
2054e98e3e1Schristos 
2064e98e3e1Schristos int
2074e98e3e1Schristos sim_get_current_source_location (const char **  pfilename,
2084e98e3e1Schristos 				 const char **  pfunctionname,
2094e98e3e1Schristos 				 unsigned int * plineno)
2104e98e3e1Schristos {
2114e98e3e1Schristos   static int   initted = 0;
2124e98e3e1Schristos   int          mypc = get_reg (pc);
2134e98e3e1Schristos 
2144e98e3e1Schristos   if (current_bfd == NULL)
2154e98e3e1Schristos     return 0;
2164e98e3e1Schristos 
2174e98e3e1Schristos   if (!initted)
2184e98e3e1Schristos     {
2194e98e3e1Schristos       int storage;
2204e98e3e1Schristos       asection * s;
2214e98e3e1Schristos 
2224e98e3e1Schristos       initted = 1;
2234e98e3e1Schristos       memset (& info, 0, sizeof (info));
2244b169a6bSchristos       INIT_DISASSEMBLE_INFO (info, stdout, op_printf, op_styled_printf);
2254e98e3e1Schristos       info.read_memory_func = sim_dis_read;
2264e98e3e1Schristos       info.arch = bfd_get_arch (current_bfd);
2274e98e3e1Schristos       info.mach = bfd_get_mach (current_bfd);
2284e98e3e1Schristos       if (info.mach == 0)
2294e98e3e1Schristos 	info.arch = bfd_arch_rx;
2304e98e3e1Schristos 
2314e98e3e1Schristos       disassemble_init_for_target (& info);
2324e98e3e1Schristos 
2334e98e3e1Schristos       storage = bfd_get_symtab_upper_bound (current_bfd);
2344e98e3e1Schristos       if (storage > 0)
2354e98e3e1Schristos 	{
2364e98e3e1Schristos 	  symtab = (asymbol **) malloc (storage);
2374e98e3e1Schristos 	  symcount = bfd_canonicalize_symtab (current_bfd, symtab);
2384e98e3e1Schristos 	  symcount = remove_useless_symbols (symtab, symcount);
2394e98e3e1Schristos 	  qsort (symtab, symcount, sizeof (asymbol *), compare_symbols);
2404e98e3e1Schristos 	}
2414e98e3e1Schristos 
2424e98e3e1Schristos       for (s = current_bfd->sections; s; s = s->next)
2434e98e3e1Schristos 	{
2444e98e3e1Schristos 	  if (s->flags & SEC_CODE || code_section == 0)
2454e98e3e1Schristos 	    {
2464e98e3e1Schristos 	      code_section = s;
2478dffb485Schristos 	      code_base = bfd_section_lma (s);
2484e98e3e1Schristos 	      break;
2494e98e3e1Schristos 	    }
2504e98e3e1Schristos 	}
2514e98e3e1Schristos     }
2524e98e3e1Schristos 
2534e98e3e1Schristos   *pfilename = *pfunctionname = NULL;
2544e98e3e1Schristos   *plineno = 0;
2554e98e3e1Schristos 
2564e98e3e1Schristos   bfd_find_nearest_line
2574e98e3e1Schristos     (current_bfd, code_section, symtab, mypc - code_base,
2584e98e3e1Schristos      pfilename, pfunctionname, plineno);
2594e98e3e1Schristos 
2604e98e3e1Schristos   return 1;
2614e98e3e1Schristos }
2624e98e3e1Schristos 
2634e98e3e1Schristos void
2644e98e3e1Schristos sim_disasm_one (void)
2654e98e3e1Schristos {
2664e98e3e1Schristos   static int           last_sym = -1;
2674e98e3e1Schristos   static const char *  prev_filename = "";
2684e98e3e1Schristos   static int           prev_lineno = 0;
2694e98e3e1Schristos   const char *  filename;
2704e98e3e1Schristos   const char *  functionname;
2714e98e3e1Schristos   unsigned int  lineno;
2724e98e3e1Schristos   int           sym, bestaddr;
2734e98e3e1Schristos   int           min, max, i;
2744e98e3e1Schristos   int           save_trace = trace;
2754e98e3e1Schristos   int           mypc = get_reg (pc);
2764e98e3e1Schristos 
2774e98e3e1Schristos   if (! sim_get_current_source_location (& filename, & functionname, & lineno))
2784e98e3e1Schristos     return;
2794e98e3e1Schristos 
2804e98e3e1Schristos   trace = 0;
2814e98e3e1Schristos 
2824e98e3e1Schristos   if (filename && functionname && lineno)
2834e98e3e1Schristos     {
2844e98e3e1Schristos       if (lineno != prev_lineno || strcmp (prev_filename, filename))
2854e98e3e1Schristos 	{
2864e98e3e1Schristos 	  char *       the_line = load_file_and_line (filename, lineno);
2874e98e3e1Schristos 	  const char * slash = strrchr (filename, '/');
2884e98e3e1Schristos 
2894e98e3e1Schristos 	  if (!slash)
2904e98e3e1Schristos 	    slash = filename;
2914e98e3e1Schristos 	  else
2924e98e3e1Schristos 	    slash++;
2934e98e3e1Schristos 	  printf
2944e98e3e1Schristos 	    ("========================================"
2954e98e3e1Schristos 	     "=====================================\n");
2964e98e3e1Schristos 	  printf ("\033[37;41m %s:%d: \033[33;40m %s\033[K\033[0m\n",
2974e98e3e1Schristos 		  slash, lineno, the_line);
2984e98e3e1Schristos 	}
2994e98e3e1Schristos       prev_lineno = lineno;
3004e98e3e1Schristos       prev_filename = filename;
3014e98e3e1Schristos     }
3024e98e3e1Schristos 
3034e98e3e1Schristos   min = -1;
3044e98e3e1Schristos   max = symcount;
3054e98e3e1Schristos   while (min < max - 1)
3064e98e3e1Schristos     {
3074e98e3e1Schristos       bfd_vma sa;
3084e98e3e1Schristos 
3094e98e3e1Schristos       sym = (min + max) / 2;
3104e98e3e1Schristos       sa = bfd_asymbol_value (symtab[sym]);
3114e98e3e1Schristos       /*printf("checking %4d %08x %s\n",
3124e98e3e1Schristos 	sym, sa, bfd_asymbol_name (symtab[sym])); */
3134e98e3e1Schristos       if (sa > mypc)
3144e98e3e1Schristos 	max = sym;
3154e98e3e1Schristos       else if (sa < mypc)
3164e98e3e1Schristos 	min = sym;
3174e98e3e1Schristos       else
3184e98e3e1Schristos 	{
3194e98e3e1Schristos 	  min = sym;
3204e98e3e1Schristos 	  break;
3214e98e3e1Schristos 	}
3224e98e3e1Schristos     }
3234e98e3e1Schristos 
3244e98e3e1Schristos   if (min != -1 && min != last_sym)
3254e98e3e1Schristos     {
3264e98e3e1Schristos       bestaddr = bfd_asymbol_value (symtab[min]);
3274e98e3e1Schristos       printf ("\033[43;30m%s", bfd_asymbol_name (symtab[min]));
3284e98e3e1Schristos       if (bestaddr != mypc)
3294e98e3e1Schristos 	printf ("+%d", mypc - bestaddr);
3304e98e3e1Schristos       printf (":\t\t\t\033[0m\n");
3314e98e3e1Schristos       last_sym = min;
3324e98e3e1Schristos #if 0
3334e98e3e1Schristos       if (trace == 1)
3344e98e3e1Schristos 	if (strcmp (bfd_asymbol_name (symtab[min]), "abort") == 0
3354e98e3e1Schristos 	    || strcmp (bfd_asymbol_name (symtab[min]), "exit") == 0)
3364e98e3e1Schristos 	  trace = 0;
3374e98e3e1Schristos #endif
3384e98e3e1Schristos     }
3394e98e3e1Schristos 
3404e98e3e1Schristos   opbuf[0] = 0;
3414e98e3e1Schristos #ifdef CYCLE_ACCURATE
3424e98e3e1Schristos   printf ("\033[33m %04u %06x: ", (int)(regs.cycle_count % 10000), mypc);
3434e98e3e1Schristos #else
3444e98e3e1Schristos   printf ("\033[33m %06x: ", mypc);
3454e98e3e1Schristos 
3464e98e3e1Schristos #endif
3474e98e3e1Schristos 
3484e98e3e1Schristos   max = print_insn_rx (mypc, & info);
3494e98e3e1Schristos 
3504e98e3e1Schristos   for (i = 0; i < max; i++)
3514e98e3e1Schristos     {
3524e98e3e1Schristos       if (rx_big_endian)
3534e98e3e1Schristos 	printf ("%02x", mem_get_qi ((mypc + i) ^ 3));
3544e98e3e1Schristos       else
3554e98e3e1Schristos 	printf ("%02x", mem_get_qi (mypc + i));
3564e98e3e1Schristos     }
3574e98e3e1Schristos 
3584e98e3e1Schristos   do
3594e98e3e1Schristos     {
3604e98e3e1Schristos       printf ("  ");
3614e98e3e1Schristos       i ++;
3624e98e3e1Schristos     }
3634e98e3e1Schristos   while (i < 6);
3644e98e3e1Schristos 
3654e98e3e1Schristos   printf ("%-16s  ", opbuf);
3664e98e3e1Schristos 
3674e98e3e1Schristos   printf ("\033[0m\n");
3684e98e3e1Schristos   trace = save_trace;
3694e98e3e1Schristos }
370