diff options
Diffstat (limited to 'sim/msp430/trace.c')
-rw-r--r-- | sim/msp430/trace.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/sim/msp430/trace.c b/sim/msp430/trace.c new file mode 100644 index 0000000..a86ea88 --- /dev/null +++ b/sim/msp430/trace.c @@ -0,0 +1,318 @@ +/* trace.c --- tracing output for the MSP430 simulator. + + Copyright (C) 2005, 2007-2013 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/>. +*/ + + +#include "config.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" + +static int +sim_dis_read (bfd_vma memaddr, bfd_byte * ptr, unsigned int length, + struct disassemble_info *info) +{ + 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) +{ + 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; + + if (sym->name[0] == '.' && sym->name[1] == 'L') + continue; + + /* If the symbol ends in ^A or ^B it is + an assembler generated local label. */ + if (sym->name[strlen (sym->name) - 1] < 32) + continue; + + *out_ptr++ = sym; + } + return out_ptr - symbols; +} + +static int +compare_symbols (const PTR ap, const PTR 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 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 +msp430_trace_init (bfd *prog) +{ + current_bfd = prog; +} + +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; + + 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 *file = fopen (found_filename, "rb"); + fread (f->data, 1, s.st_size, file); + f->data[s.st_size] = 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 +msp430_get_current_source_location (int mypc, + const char ** pfilename, + const char ** pfunctionname, + unsigned int * plineno) +{ + static int initted = 0; + + if (current_bfd == NULL) + { + printf("no bfd\n"); + return 0; + } + + if (!initted) + { + int storage; + asection * s; + + initted = 1; + memset (& info, 0, sizeof (info)); + INIT_DISASSEMBLE_INFO (info, stdout, op_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_msp430; + + 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 (current_bfd, 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 +msp430_trace_one (int mypc) +{ + 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; + + if (! msp430_get_current_source_location (mypc, & filename, & functionname, & lineno)) + return; + + 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 ++; + fprintf + (stderr, "========================================" + "=====================================\n"); + fprintf (stderr, "\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]); + fprintf (stderr, "\033[43;30m%s", bfd_asymbol_name (symtab[min])); + if (bestaddr != mypc) + fprintf (stderr, "+%d", mypc - bestaddr); + fprintf (stderr, ":\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 + } +} |