* elf64-ppc.c (dec_dynrel_count): Don't error when elf_gc_sweep_symbol
[external/binutils.git] / sim / common / cgen-trace.c
index 82a20a5..b5e22cb 100644 (file)
@@ -1,26 +1,31 @@
 /* Tracing support for CGEN-based simulators.
-   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1996-2013 Free Software Foundation, Inc.
    Contributed by Cygnus Support.
 
 This file is part of GDB, the GNU debugger.
 
 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 2, or (at your option)
-any later version.
+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, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+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 "sim-main.h"
+#include "config.h"
+#include <errno.h>
+#include "dis-asm.h"
 #include "bfd.h"
-#include "cpu-opc.h"
+#include "sim-main.h"
+#include "sim-fpu.h"
+
+#undef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
 
 #ifndef SIZE_INSTRUCTION
 #define SIZE_INSTRUCTION 16
@@ -47,7 +52,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #endif
 
 #ifndef SIZE_TRACE_BUF
-#define SIZE_TRACE_BUF 256
+#define SIZE_TRACE_BUF 1024
 #endif
 
 /* Text is queued in TRACE_BUF because we want to output the insn's cycle
@@ -68,7 +73,6 @@ static int printed_result_p;
    Set by trace_insn, used by trace_insn_fini.
    ??? Move to SIM_CPU to support heterogeneous multi-cpu case.  */
 static const struct cgen_insn *current_insn;
-static CGEN_FIELDS insn_fields;
 static const struct argbuf *current_abuf;
 
 void
@@ -121,7 +125,7 @@ trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
 #if 0
   /* Print insn results.  */
   {
-    const CGEN_OPERAND_INSTANCE *opinst = CGEN_INSN_OPERANDS (current_insn);
+    const CGEN_OPINST *opinst = CGEN_INSN_OPERANDS (current_insn);
 
     if (opinst)
       {
@@ -129,16 +133,16 @@ trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
        int indices[MAX_OPERAND_INSTANCES];
 
        /* Fetch the operands used by the insn.  */
-       /* FIXME: Add fn ptr to CGEN_OPCODE_DESC.  */
-       CGEN_SYM (get_insn_operands) (STATE_OPCODE_TABLE (sd), current_insn,
+       /* FIXME: Add fn ptr to CGEN_CPU_DESC.  */
+       CGEN_SYM (get_insn_operands) (CPU_CPU_DESC (cpu), current_insn,
                                      0, CGEN_FIELDS_BITSIZE (&insn_fields),
                                      indices);
 
        for (i = 0;
-            CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END;
+            CGEN_OPINST_TYPE (opinst) != CGEN_OPINST_END;
             ++i, ++opinst)
          {
-           if (CGEN_OPERAND_INSTANCE_TYPE (opinst) == CGEN_OPERAND_INSTANCE_OUTPUT)
+           if (CGEN_OPINST_TYPE (opinst) == CGEN_OPINST_OUTPUT)
              trace_result (cpu, current_insn, opinst, indices[i]);
          }
       }
@@ -155,7 +159,7 @@ trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
 
 void
 trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
-           const struct argbuf *abuf, PCADDR pc)
+           const struct argbuf *abuf, IADDR pc)
 {
   char disasm_buf[50];
 
@@ -170,7 +174,7 @@ trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
       return;
     }
 
-  sim_disassemble_insn (cpu, opcode, abuf, pc, disasm_buf, &insn_fields);
+  CPU_DISASSEMBLER (cpu) (cpu, opcode, abuf, pc, disasm_buf);
   trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
                NULL, 0,
                "%s%-*s",
@@ -179,7 +183,7 @@ trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
 }
 
 void
-trace_extract (SIM_CPU *cpu, PCADDR pc, char *name, ...)
+trace_extract (SIM_CPU *cpu, IADDR pc, char *name, ...)
 {
   va_list args;
   int printed_one_p = 0;
@@ -188,7 +192,7 @@ trace_extract (SIM_CPU *cpu, PCADDR pc, char *name, ...)
   va_start (args, name);
 
   trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ",
-               SIZE_PC, pc, name);
+               SIZE_PC, (unsigned long) pc, name);
 
   do {
     int type,ival;
@@ -232,6 +236,19 @@ trace_result (SIM_CPU *cpu, char *name, int type, ...)
     default :
       cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int));
       break;
+    case 'f':
+      {
+       DI di;
+       sim_fpu f;
+
+       /* this is separated from previous line for sunos cc */
+       di = va_arg (args, DI);
+       sim_fpu_64to (&f, di);
+
+       cgen_trace_printf (cpu, "%s <- ", name);
+       sim_fpu_printn_fpu (&f, (sim_fpu_print_func *) cgen_trace_printf, 4, cpu);
+       break;
+      }
     case 'D' :
       {
        DI di;
@@ -276,3 +293,144 @@ cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...)
 
   va_end (args);
 }
+\f
+/* Disassembly support.  */
+
+/* sprintf to a "stream" */
+
+int
+sim_disasm_sprintf VPARAMS ((SFILE *f, const char *format, ...))
+{
+#ifndef __STDC__
+  SFILE *f;
+  const char *format;
+#endif
+  int n;
+  va_list args;
+
+  VA_START (args, format);
+#ifndef __STDC__
+  f = va_arg (args, SFILE *);
+  format = va_arg (args, char *);
+#endif
+  vsprintf (f->current, format, args);
+  f->current += n = strlen (f->current);
+  va_end (args);
+  return n;
+}
+
+/* Memory read support for an opcodes disassembler.  */
+
+int
+sim_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+                       struct disassemble_info *info)
+{
+  SIM_CPU *cpu = (SIM_CPU *) info->application_data;
+  SIM_DESC sd = CPU_STATE (cpu);
+  unsigned length_read;
+
+  length_read = sim_core_read_buffer (sd, cpu, read_map, myaddr, memaddr,
+                                     length);
+  if (length_read != length)
+    return EIO;
+  return 0;
+}
+
+/* Memory error support for an opcodes disassembler.  */
+
+void
+sim_disasm_perror_memory (int status, bfd_vma memaddr,
+                         struct disassemble_info *info)
+{
+  if (status != EIO)
+    /* Can't happen.  */
+    info->fprintf_func (info->stream, "Unknown error %d.", status);
+  else
+    /* Actually, address between memaddr and memaddr + len was
+       out of bounds.  */
+    info->fprintf_func (info->stream,
+                       "Address 0x%x is out of bounds.",
+                       (int) memaddr);
+}
+
+/* Disassemble using the CGEN opcode table.
+   ??? While executing an instruction, the insn has been decoded and all its
+   fields have been extracted.  It is certainly possible to do the disassembly
+   with that data.  This seems simpler, but maybe in the future the already
+   extracted fields will be used.  */
+
+void
+sim_cgen_disassemble_insn (SIM_CPU *cpu, const CGEN_INSN *insn,
+                          const ARGBUF *abuf, IADDR pc, char *buf)
+{
+  unsigned int length;
+  unsigned int base_length;
+  unsigned long insn_value;
+  struct disassemble_info disasm_info;
+  SFILE sfile;
+  union {
+    unsigned8 bytes[CGEN_MAX_INSN_SIZE];
+    unsigned16 shorts[8];
+    unsigned32 words[4];
+  } insn_buf;
+  SIM_DESC sd = CPU_STATE (cpu);
+  CGEN_CPU_DESC cd = CPU_CPU_DESC (cpu);
+  CGEN_EXTRACT_INFO ex_info;
+  CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
+  int insn_bit_length = CGEN_INSN_BITSIZE (insn);
+  int insn_length = insn_bit_length / 8;
+
+  sfile.buffer = sfile.current = buf;
+  INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile,
+                        (fprintf_ftype) sim_disasm_sprintf);
+  disasm_info.endian =
+    (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG
+     : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE
+     : BFD_ENDIAN_UNKNOWN);
+
+  length = sim_core_read_buffer (sd, cpu, read_map, &insn_buf, pc,
+                                insn_length);
+
+  if (length != insn_length)
+  {
+    sim_io_error (sd, "unable to read address %x", pc);
+  }
+
+  /* If the entire insn will fit into an integer, then do it. Otherwise, just
+     use the bits of the base_insn.  */
+  if (insn_bit_length <= 32)
+    base_length = insn_bit_length;
+  else
+    base_length = min (cd->base_insn_bitsize, insn_bit_length);
+  switch (base_length)
+    {
+    case 0 : return; /* fake insn, typically "compile" (aka "invalid") */
+    case 8 : insn_value = insn_buf.bytes[0]; break;
+    case 16 : insn_value = T2H_2 (insn_buf.shorts[0]); break;
+    case 32 : insn_value = T2H_4 (insn_buf.words[0]); break;
+    default: abort ();
+    }
+
+  disasm_info.buffer_vma = pc;
+  disasm_info.buffer = insn_buf.bytes;
+  disasm_info.buffer_length = length;
+
+  ex_info.dis_info = (PTR) &disasm_info;
+  ex_info.valid = (1 << length) - 1;
+  ex_info.insn_bytes = insn_buf.bytes;
+
+  length = (*CGEN_EXTRACT_FN (cd, insn)) (cd, insn, &ex_info, insn_value, fields, pc);
+  /* Result of extract fn is in bits.  */
+  /* ??? This assumes that each instruction has a fixed length (and thus
+     for insns with multiple versions of variable lengths they would each
+     have their own table entry).  */
+  if (length == insn_bit_length)
+    {
+      (*CGEN_PRINT_FN (cd, insn)) (cd, &disasm_info, insn, fields, pc, length);
+    }
+  else
+    {
+      /* This shouldn't happen, but aborting is too drastic.  */
+      strcpy (buf, "***unknown***");
+    }
+}