|  | /* trace.c --- tracing output for the RL78 simulator. | 
|  |  | 
|  | Copyright (C) 2005-2022 Free Software Foundation, Inc. | 
|  | Contributed by Red Hat, Inc. | 
|  |  | 
|  | This file is part of the GNU simulators. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|  | */ | 
|  |  | 
|  | /* This must come before any other includes.  */ | 
|  | #include "defs.h" | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <stdarg.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <ctype.h> | 
|  |  | 
|  | #include "libiberty.h" | 
|  | #include "bfd.h" | 
|  | #include "dis-asm.h" | 
|  |  | 
|  | #include "cpu.h" | 
|  | #include "mem.h" | 
|  | #include "load.h" | 
|  | #include "trace.h" | 
|  |  | 
|  | static disassembler_ftype rl78_disasm_fn = NULL; | 
|  |  | 
|  | static int | 
|  | sim_dis_read (bfd_vma memaddr, bfd_byte * ptr, unsigned int length, | 
|  | struct disassemble_info *info) | 
|  | { | 
|  | mem_get_blk (memaddr, ptr, length); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Filter out (in place) symbols that are useless for disassembly. | 
|  | COUNT is the number of elements in SYMBOLS. | 
|  | Return the number of useful symbols. */ | 
|  |  | 
|  | static long | 
|  | remove_useless_symbols (asymbol ** symbols, long count) | 
|  | { | 
|  | register asymbol **in_ptr = symbols, **out_ptr = symbols; | 
|  |  | 
|  | while (-- count >= 0) | 
|  | { | 
|  | asymbol *sym = *in_ptr ++; | 
|  |  | 
|  | if (strstr (sym->name, "gcc2_compiled")) | 
|  | continue; | 
|  | if (sym->name == NULL || sym->name[0] == '\0') | 
|  | continue; | 
|  | if (sym->flags & (BSF_DEBUGGING)) | 
|  | continue; | 
|  | if (bfd_is_und_section (sym->section) | 
|  | || bfd_is_com_section (sym->section)) | 
|  | continue; | 
|  |  | 
|  | *out_ptr++ = sym; | 
|  | } | 
|  | return out_ptr - symbols; | 
|  | } | 
|  |  | 
|  | static int | 
|  | compare_symbols (const void *ap, const void *bp) | 
|  | { | 
|  | const asymbol *a = *(const asymbol **) ap; | 
|  | const asymbol *b = *(const asymbol **) bp; | 
|  |  | 
|  | if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) | 
|  | return 1; | 
|  | else if (bfd_asymbol_value (a) < bfd_asymbol_value (b)) | 
|  | return -1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static char opbuf[1000]; | 
|  |  | 
|  | static int | 
|  | op_printf (char *buf, char *fmt, ...) | 
|  | { | 
|  | int ret; | 
|  | va_list ap; | 
|  |  | 
|  | va_start (ap, fmt); | 
|  | ret = vsprintf (opbuf + strlen (opbuf), fmt, ap); | 
|  | va_end (ap); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int | 
|  | op_styled_printf (char *buf, enum disassembler_style style, char *fmt, ...) | 
|  | { | 
|  | int ret; | 
|  | va_list ap; | 
|  |  | 
|  | va_start (ap, fmt); | 
|  | ret = vsprintf (opbuf + strlen (opbuf), fmt, ap); | 
|  | va_end (ap); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static bfd *       current_bfd = NULL; | 
|  | static asymbol **  symtab = NULL; | 
|  | static int         symcount = 0; | 
|  | static asection *  code_section = NULL; | 
|  | static bfd_vma     code_base = 0; | 
|  | static struct disassemble_info info; | 
|  |  | 
|  | void | 
|  | sim_disasm_init (bfd *prog) | 
|  | { | 
|  | current_bfd = prog; | 
|  | rl78_disasm_fn = NULL; | 
|  | } | 
|  |  | 
|  | typedef struct Files | 
|  | { | 
|  | struct Files *next; | 
|  | char *filename; | 
|  | int nlines; | 
|  | char **lines; | 
|  | char *data; | 
|  | } Files; | 
|  | Files *files = 0; | 
|  |  | 
|  | static char * | 
|  | load_file_and_line (const char *filename, int lineno) | 
|  | { | 
|  | Files *f; | 
|  | for (f = files; f; f = f->next) | 
|  | if (strcmp (f->filename, filename) == 0) | 
|  | break; | 
|  | if (!f) | 
|  | { | 
|  | int i; | 
|  | struct stat s; | 
|  | const char *found_filename, *slash; | 
|  | FILE *file; | 
|  | size_t ret; | 
|  |  | 
|  | found_filename = filename; | 
|  | while (1) | 
|  | { | 
|  | if (stat (found_filename, &s) == 0) | 
|  | break; | 
|  | slash = strchr (found_filename, '/'); | 
|  | if (!slash) | 
|  | return ""; | 
|  | found_filename = slash + 1; | 
|  | } | 
|  |  | 
|  | f = (Files *) xmalloc (sizeof (Files)); | 
|  | f->next = files; | 
|  | files = f; | 
|  | f->filename = xstrdup (filename); | 
|  | f->data = (char *) xmalloc (s.st_size + 2); | 
|  | file = fopen (found_filename, "rb"); | 
|  | ret = fread (f->data, 1, s.st_size, file); | 
|  | f->data[ret] = 0; | 
|  | fclose (file); | 
|  |  | 
|  | f->nlines = 1; | 
|  | for (i = 0; i < s.st_size; i ++) | 
|  | if (f->data[i] == '\n') | 
|  | f->nlines ++; | 
|  | f->lines = (char **) xmalloc (f->nlines * sizeof (char *)); | 
|  | f->lines[0] = f->data; | 
|  | f->nlines = 1; | 
|  | for (i = 0; i < s.st_size; i ++) | 
|  | if (f->data[i] == '\n') | 
|  | { | 
|  | f->lines[f->nlines] = f->data + i + 1; | 
|  | while (*f->lines[f->nlines] == ' ' | 
|  | || *f->lines[f->nlines] == '\t') | 
|  | f->lines[f->nlines] ++; | 
|  | f->nlines ++; | 
|  | f->data[i] = 0; | 
|  | } | 
|  | } | 
|  | if (lineno < 1 || lineno > f->nlines) | 
|  | return ""; | 
|  | return f->lines[lineno - 1]; | 
|  | } | 
|  |  | 
|  | int | 
|  | sim_get_current_source_location (const char **  pfilename, | 
|  | const char **  pfunctionname, | 
|  | unsigned int * plineno) | 
|  | { | 
|  | static int   initted = 0; | 
|  | int          mypc = pc; | 
|  |  | 
|  | if (current_bfd == NULL) | 
|  | return 0; | 
|  |  | 
|  | if (!initted) | 
|  | { | 
|  | int storage; | 
|  | asection * s; | 
|  |  | 
|  | initted = 1; | 
|  | memset (& info, 0, sizeof (info)); | 
|  | INIT_DISASSEMBLE_INFO (info, stdout, op_printf, op_styled_printf); | 
|  | info.read_memory_func = sim_dis_read; | 
|  | info.arch = bfd_get_arch (current_bfd); | 
|  | info.mach = bfd_get_mach (current_bfd); | 
|  | if (info.mach == 0) | 
|  | info.arch = bfd_arch_rl78; | 
|  |  | 
|  | disassemble_init_for_target (& info); | 
|  |  | 
|  | storage = bfd_get_symtab_upper_bound (current_bfd); | 
|  | if (storage > 0) | 
|  | { | 
|  | symtab = (asymbol **) xmalloc (storage); | 
|  | symcount = bfd_canonicalize_symtab (current_bfd, symtab); | 
|  | symcount = remove_useless_symbols (symtab, symcount); | 
|  | qsort (symtab, symcount, sizeof (asymbol *), compare_symbols); | 
|  | } | 
|  |  | 
|  | for (s = current_bfd->sections; s; s = s->next) | 
|  | { | 
|  | if (s->flags & SEC_CODE || code_section == 0) | 
|  | { | 
|  | code_section = s; | 
|  | code_base = bfd_section_lma (s); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | *pfilename = *pfunctionname = NULL; | 
|  | *plineno = 0; | 
|  |  | 
|  | bfd_find_nearest_line | 
|  | (current_bfd, code_section, symtab, mypc - code_base, | 
|  | pfilename, pfunctionname, plineno); | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void | 
|  | sim_disasm_one (void) | 
|  | { | 
|  | static int           last_sym = -1; | 
|  | static const char *  prev_filename = ""; | 
|  | static int           prev_lineno = 0; | 
|  | const char *  filename; | 
|  | const char *  functionname; | 
|  | unsigned int  lineno; | 
|  | int           sym, bestaddr; | 
|  | int           min, max, i; | 
|  | int           save_trace = trace; | 
|  | int           mypc = pc; | 
|  |  | 
|  | if (! sim_get_current_source_location (& filename, & functionname, & lineno)) | 
|  | return; | 
|  |  | 
|  | trace = 0; | 
|  |  | 
|  | if (!rl78_disasm_fn) | 
|  | { | 
|  | if (rl78_g10_mode) | 
|  | rl78_disasm_fn = print_insn_rl78_g10; | 
|  | else if (g14_multiply) | 
|  | rl78_disasm_fn = print_insn_rl78_g14; | 
|  | else if (g13_multiply) | 
|  | rl78_disasm_fn = print_insn_rl78_g13; | 
|  | else | 
|  | rl78_disasm_fn = print_insn_rl78; | 
|  | } | 
|  |  | 
|  | if (filename && functionname && lineno) | 
|  | { | 
|  | if (lineno != prev_lineno || strcmp (prev_filename, filename)) | 
|  | { | 
|  | char *       the_line = load_file_and_line (filename, lineno); | 
|  | const char * slash = strrchr (filename, '/'); | 
|  |  | 
|  | if (!slash) | 
|  | slash = filename; | 
|  | else | 
|  | slash ++; | 
|  | printf | 
|  | ("========================================" | 
|  | "=====================================\n"); | 
|  | printf ("\033[37;41m %s:%d: \033[33;40m %s\033[K\033[0m\n", | 
|  | slash, lineno, the_line); | 
|  | } | 
|  | prev_lineno = lineno; | 
|  | prev_filename = filename; | 
|  | } | 
|  |  | 
|  | min = -1; | 
|  | max = symcount; | 
|  | while (min < max - 1) | 
|  | { | 
|  | bfd_vma sa; | 
|  |  | 
|  | sym = (min + max) / 2; | 
|  | sa = bfd_asymbol_value (symtab[sym]); | 
|  | /*printf ("checking %4d %08x %s\n", | 
|  | sym, sa, bfd_asymbol_name (symtab[sym])); */ | 
|  | if (sa > mypc) | 
|  | max = sym; | 
|  | else if (sa < mypc) | 
|  | min = sym; | 
|  | else | 
|  | { | 
|  | min = sym; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (min != -1 && min != last_sym) | 
|  | { | 
|  | bestaddr = bfd_asymbol_value (symtab[min]); | 
|  | printf ("\033[43;30m%s", bfd_asymbol_name (symtab[min])); | 
|  | if (bestaddr != mypc) | 
|  | printf ("+%d", mypc - bestaddr); | 
|  | printf (":\t\t\t\033[0m\n"); | 
|  | last_sym = min; | 
|  | #if 0 | 
|  | if (trace == 1) | 
|  | if (strcmp (bfd_asymbol_name (symtab[min]), "abort") == 0 | 
|  | || strcmp (bfd_asymbol_name (symtab[min]), "exit") == 0) | 
|  | trace = 0; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #define TCR0	0xf0180 | 
|  |  | 
|  | opbuf[0] = 0; | 
|  | #ifdef CYCLE_ACCURATE | 
|  | printf ("\033[33m %04u %06x: ", (int)(regs.cycle_count % 10000), mypc); | 
|  | #else | 
|  | printf ("\033[33m %08llx %06x: ", total_clocks, mypc); | 
|  | #endif | 
|  |  | 
|  | max = rl78_disasm_fn (mypc, & info); | 
|  |  | 
|  | for (i = 0; i < max; i ++) | 
|  | printf ("%02x", mem_get_qi (mypc + i)); | 
|  |  | 
|  | do | 
|  | { | 
|  | printf ("  "); | 
|  | i ++; | 
|  | } | 
|  | while (i < 6); | 
|  |  | 
|  | printf ("%-16s  ", opbuf); | 
|  |  | 
|  | printf ("\033[0m\n"); | 
|  | trace = save_trace; | 
|  | } |