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