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