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