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