1/* trace.c --- tracing output for the M32C simulator. 2 3Copyright (C) 2005-2020 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#include "config.h" 22#include <stdio.h> 23#include <stdarg.h> 24#include <string.h> 25#include <stdlib.h> 26#include <sys/types.h> 27#include <sys/stat.h> 28#include <ctype.h> 29 30#include "bfd.h" 31#include "dis-asm.h" 32#include "m32c-desc.h" 33 34#include "cpu.h" 35#include "mem.h" 36#include "load.h" 37#include "trace.h" 38 39static int 40sim_dis_read (bfd_vma memaddr, bfd_byte * ptr, unsigned int length, 41 struct disassemble_info *info) 42{ 43 mem_get_blk (memaddr, ptr, length); 44 return 0; 45} 46 47/* Filter out (in place) symbols that are useless for disassembly. 48 COUNT is the number of elements in SYMBOLS. 49 Return the number of useful symbols. */ 50 51static long 52remove_useless_symbols (asymbol ** symbols, long count) 53{ 54 register asymbol **in_ptr = symbols, **out_ptr = symbols; 55 56 while (--count >= 0) 57 { 58 asymbol *sym = *in_ptr++; 59 60 if (strstr (sym->name, "gcc2_compiled")) 61 continue; 62 if (sym->name == NULL || sym->name[0] == '\0') 63 continue; 64 if (sym->flags & (BSF_DEBUGGING)) 65 continue; 66 if (bfd_is_und_section (sym->section) 67 || bfd_is_com_section (sym->section)) 68 continue; 69 70 *out_ptr++ = sym; 71 } 72 return out_ptr - symbols; 73} 74 75static int 76compare_symbols (const PTR ap, const PTR bp) 77{ 78 const asymbol *a = *(const asymbol **) ap; 79 const asymbol *b = *(const asymbol **) bp; 80 81 if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) 82 return 1; 83 else if (bfd_asymbol_value (a) < bfd_asymbol_value (b)) 84 return -1; 85 return 0; 86} 87 88static char opbuf[1000]; 89 90static int 91op_printf (char *buf, char *fmt, ...) 92{ 93 int ret; 94 va_list ap; 95 96 va_start (ap, fmt); 97 ret = vsprintf (opbuf + strlen (opbuf), fmt, ap); 98 va_end (ap); 99 return ret; 100} 101 102static bfd *current_bfd; 103 104void 105sim_disasm_init (bfd * prog) 106{ 107 current_bfd = prog; 108} 109 110typedef struct Files 111{ 112 struct Files *next; 113 char *filename; 114 int nlines; 115 char **lines; 116 char *data; 117} Files; 118Files *files = 0; 119 120static char * 121load_file_and_line (const char *filename, int lineno) 122{ 123 Files *f; 124 for (f = files; f; f = f->next) 125 if (strcmp (f->filename, filename) == 0) 126 break; 127 if (!f) 128 { 129 int i; 130 struct stat s; 131 const char *found_filename, *slash; 132 FILE *file; 133 134 found_filename = filename; 135 while (1) 136 { 137 if (stat (found_filename, &s) == 0) 138 break; 139 slash = strchr (found_filename, '/'); 140 if (!slash) 141 return ""; 142 found_filename = slash + 1; 143 } 144 145 f = (Files *) malloc (sizeof (Files)); 146 f->next = files; 147 files = f; 148 f->filename = strdup (filename); 149 f->data = (char *) malloc (s.st_size + 2); 150 file = fopen (found_filename, "rb"); 151 fread (f->data, 1, s.st_size, file); 152 f->data[s.st_size] = 0; 153 fclose (file); 154 155 f->nlines = 1; 156 for (i = 0; i < s.st_size; i++) 157 if (f->data[i] == '\n') 158 f->nlines++; 159 f->lines = (char **) malloc (f->nlines * sizeof (char *)); 160 f->lines[0] = f->data; 161 f->nlines = 1; 162 for (i = 0; i < s.st_size; i++) 163 if (f->data[i] == '\n') 164 { 165 f->lines[f->nlines] = f->data + i + 1; 166 while (*f->lines[f->nlines] == ' ' 167 || *f->lines[f->nlines] == '\t') 168 f->lines[f->nlines]++; 169 f->nlines++; 170 f->data[i] = 0; 171 } 172 } 173 if (lineno < 1 || lineno > f->nlines) 174 return ""; 175 return f->lines[lineno - 1]; 176} 177 178void 179sim_disasm_one (void) 180{ 181 static int initted = 0; 182 static asymbol **symtab = 0; 183 static int symcount = 0; 184 static int last_sym = -1; 185 static struct disassemble_info info; 186 int storage, sym, bestaddr; 187 int min, max, i; 188 static asection *code_section = 0; 189 static bfd_vma code_base = 0; 190 asection *s; 191 int save_trace = trace; 192 193 static const char *prev_filename = ""; 194 static int prev_lineno = 0; 195 const char *filename; 196 const char *functionname; 197 unsigned int lineno; 198 199 int mypc = get_reg (pc); 200 201 if (current_bfd == 0) 202 return; 203 204 trace = 0; 205 206 if (!initted) 207 { 208 initted = 1; 209 memset (&info, 0, sizeof (info)); 210 INIT_DISASSEMBLE_INFO (info, stdout, op_printf); 211 info.read_memory_func = sim_dis_read; 212 info.arch = bfd_get_arch (current_bfd); 213 info.mach = bfd_get_mach (current_bfd); 214 if (info.mach == 0) 215 { 216 info.arch = bfd_arch_m32c; 217 info.mach = default_machine; 218 } 219 disassemble_init_for_target (&info); 220 221 storage = bfd_get_symtab_upper_bound (current_bfd); 222 if (storage > 0) 223 { 224 symtab = (asymbol **) malloc (storage); 225 symcount = bfd_canonicalize_symtab (current_bfd, symtab); 226 symcount = remove_useless_symbols (symtab, symcount); 227 qsort (symtab, symcount, sizeof (asymbol *), compare_symbols); 228 } 229 for (s = current_bfd->sections; s; s = s->next) 230 { 231 if (s->flags & SEC_CODE || code_section == 0) 232 { 233 code_section = s; 234 code_base = bfd_section_lma (s); 235 break; 236 } 237 } 238 } 239 240 filename = functionname = 0; 241 lineno = 0; 242 if (bfd_find_nearest_line 243 (current_bfd, code_section, symtab, mypc - code_base, &filename, 244 &functionname, &lineno)) 245 { 246 if (filename && functionname && lineno) 247 { 248 if (lineno != prev_lineno || strcmp (prev_filename, filename)) 249 { 250 char *the_line = load_file_and_line (filename, lineno); 251 const char *slash = strrchr (filename, '/'); 252 if (!slash) 253 slash = filename; 254 else 255 slash++; 256 printf 257 ("========================================" 258 "=====================================\n"); 259 printf ("\033[37;41m %s:%d: \033[33;40m %s\033[K\033[0m\n", 260 slash, lineno, the_line); 261 } 262 prev_lineno = lineno; 263 prev_filename = filename; 264 } 265 } 266 267 { 268 min = -1; 269 max = symcount; 270 while (min < max - 1) 271 { 272 bfd_vma sa; 273 sym = (min + max) / 2; 274 sa = bfd_asymbol_value (symtab[sym]); 275 /*printf("checking %4d %08x %s\n", 276 sym, sa, bfd_asymbol_name (symtab[sym])); */ 277 if (sa > mypc) 278 max = sym; 279 else if (sa < mypc) 280 min = sym; 281 else 282 { 283 min = sym; 284 break; 285 } 286 } 287 if (min != -1 && min != last_sym) 288 { 289 bestaddr = bfd_asymbol_value (symtab[min]); 290 printf ("\033[43;30m%s", bfd_asymbol_name (symtab[min])); 291 if (bestaddr != mypc) 292 printf ("+%d", mypc - bestaddr); 293 printf (":\t\t\t\033[0m\n"); 294 last_sym = min; 295#if 0 296 if (trace == 1) 297 if (strcmp (bfd_asymbol_name (symtab[min]), "abort") == 0 298 || strcmp (bfd_asymbol_name (symtab[min]), "exit") == 0) 299 trace = 0; 300#endif 301 } 302 } 303 304 opbuf[0] = 0; 305 printf ("\033[33m%06x: ", mypc); 306 max = print_insn_m32c (mypc, &info); 307 for (i = 0; i < max; i++) 308 printf ("%02x", mem_get_qi (mypc + i)); 309 for (; i < 6; i++) 310 printf (" "); 311 printf ("%-16s ", opbuf); 312 313 printf ("\033[0m\n"); 314 trace = save_trace; 315} 316