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