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 42static disassembler_ftype rl78_disasm_fn = NULL; 43 44static int 45sim_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 56static long 57remove_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 80static int 81compare_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 93static char opbuf[1000]; 94 95static int ATTRIBUTE_PRINTF (2, 3) 96op_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 107static int ATTRIBUTE_PRINTF (3, 4) 108op_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 119static bfd * current_bfd = NULL; 120static asymbol ** symtab = NULL; 121static int symcount = 0; 122static asection * code_section = NULL; 123static bfd_vma code_base = 0; 124static struct disassemble_info info; 125 126void 127sim_disasm_init (bfd *prog) 128{ 129 current_bfd = prog; 130 rl78_disasm_fn = NULL; 131} 132 133typedef struct Files 134{ 135 struct Files *next; 136 char *filename; 137 int nlines; 138 char **lines; 139 char *data; 140} Files; 141Files *files = 0; 142 143static char * 144load_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 202int 203sim_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 259void 260sim_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