diff options
author | DJ Delorie <dj@redhat.com> | 2011-11-29 03:49:09 +0000 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2011-11-29 03:49:09 +0000 |
commit | 87326c782a97fdacdd003599c8633b28114f8ed9 (patch) | |
tree | fcce7203ce754ec2a269d2dea60c76fa6985c5c7 /sim/rl78/trace.c | |
parent | 1e3a8f45c5a6e5d922e6e981d1572f2db35fb7a9 (diff) | |
download | gdb-87326c782a97fdacdd003599c8633b28114f8ed9.zip gdb-87326c782a97fdacdd003599c8633b28114f8ed9.tar.gz gdb-87326c782a97fdacdd003599c8633b28114f8ed9.tar.bz2 |
[sim]
* configure.tgt: Add rl78 support.
* configure: Regenerate.
* rl78: New directory.
* MAINTAINERS: Add myself as RL78 maintainer.
[gdb]
* NEWS: Mention RL78 simulator.
Diffstat (limited to 'sim/rl78/trace.c')
-rw-r--r-- | sim/rl78/trace.c | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/sim/rl78/trace.c b/sim/rl78/trace.c new file mode 100644 index 0000000..12f7893 --- /dev/null +++ b/sim/rl78/trace.c @@ -0,0 +1,343 @@ +/* trace.c --- tracing output for the RL78 simulator. + + Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011 + 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" + +#include "cpu.h" +#include "mem.h" +#include "load.h" + +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 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 +sim_disasm_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 +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); + 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 (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 +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 (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 = print_insn_rl78 (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; +} |