xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/cgen-trace.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
198b9484cSchristos /* Tracing support for CGEN-based simulators.
2*88241920Schristos    Copyright (C) 1996-2024 Free Software Foundation, Inc.
398b9484cSchristos    Contributed by Cygnus Support.
498b9484cSchristos 
598b9484cSchristos This file is part of GDB, the GNU debugger.
698b9484cSchristos 
798b9484cSchristos This program is free software; you can redistribute it and/or modify
898b9484cSchristos it under the terms of the GNU General Public License as published by
998b9484cSchristos the Free Software Foundation; either version 3 of the License, or
1098b9484cSchristos (at your option) any later version.
1198b9484cSchristos 
1298b9484cSchristos This program is distributed in the hope that it will be useful,
1398b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1598b9484cSchristos GNU General Public License for more details.
1698b9484cSchristos 
1798b9484cSchristos You should have received a copy of the GNU General Public License
1898b9484cSchristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1998b9484cSchristos 
204b169a6bSchristos /* This must come before any other includes.  */
214b169a6bSchristos #include "defs.h"
224b169a6bSchristos 
2398b9484cSchristos #include <errno.h>
244b169a6bSchristos #include <stdarg.h>
254b169a6bSchristos #include <stdlib.h>
264b169a6bSchristos 
2798b9484cSchristos #include "bfd.h"
284b169a6bSchristos #include "diagnostics.h"
294b169a6bSchristos #include "dis-asm.h"
304b169a6bSchristos 
3198b9484cSchristos #include "sim-main.h"
3298b9484cSchristos #include "sim-fpu.h"
334b169a6bSchristos #include "sim/callback.h"
3498b9484cSchristos 
3598b9484cSchristos #ifndef SIZE_INSTRUCTION
3698b9484cSchristos #define SIZE_INSTRUCTION 16
3798b9484cSchristos #endif
3898b9484cSchristos 
3998b9484cSchristos #ifndef SIZE_LOCATION
4098b9484cSchristos #define SIZE_LOCATION 20
4198b9484cSchristos #endif
4298b9484cSchristos 
4398b9484cSchristos #ifndef SIZE_PC
4498b9484cSchristos #define SIZE_PC 6
4598b9484cSchristos #endif
4698b9484cSchristos 
4798b9484cSchristos #ifndef SIZE_LINE_NUMBER
4898b9484cSchristos #define SIZE_LINE_NUMBER 4
4998b9484cSchristos #endif
5098b9484cSchristos 
5198b9484cSchristos #ifndef SIZE_CYCLE_COUNT
5298b9484cSchristos #define SIZE_CYCLE_COUNT 2
5398b9484cSchristos #endif
5498b9484cSchristos 
5598b9484cSchristos #ifndef SIZE_TOTAL_CYCLE_COUNT
5698b9484cSchristos #define SIZE_TOTAL_CYCLE_COUNT 9
5798b9484cSchristos #endif
5898b9484cSchristos 
5998b9484cSchristos #ifndef SIZE_TRACE_BUF
6098b9484cSchristos #define SIZE_TRACE_BUF 1024
6198b9484cSchristos #endif
6298b9484cSchristos 
6398b9484cSchristos /* Text is queued in TRACE_BUF because we want to output the insn's cycle
6498b9484cSchristos    count first but that isn't known until after the insn has executed.
6598b9484cSchristos    This also handles the queueing of trace results, TRACE_RESULT may be
6698b9484cSchristos    called multiple times for one insn.  */
6798b9484cSchristos static char trace_buf[SIZE_TRACE_BUF];
6898b9484cSchristos /* If NULL, output to stdout directly.  */
6998b9484cSchristos static char *bufptr;
7098b9484cSchristos 
7198b9484cSchristos /* Non-zero if this is the first insn in a set of parallel insns.  */
7298b9484cSchristos static int first_insn_p;
7398b9484cSchristos 
74212397c6Schristos /* For communication between cgen_trace_insn and cgen_trace_result.  */
7598b9484cSchristos static int printed_result_p;
7698b9484cSchristos 
7798b9484cSchristos /* Insn and its extracted fields.
78212397c6Schristos    Set by cgen_trace_insn, used by cgen_trace_insn_fini.
7998b9484cSchristos    ??? Move to SIM_CPU to support heterogeneous multi-cpu case.  */
8098b9484cSchristos static const struct cgen_insn *current_insn;
8198b9484cSchristos static const struct argbuf *current_abuf;
8298b9484cSchristos 
8398b9484cSchristos void
84212397c6Schristos cgen_trace_insn_init (SIM_CPU *cpu, int first_p)
8598b9484cSchristos {
8698b9484cSchristos   bufptr = trace_buf;
8798b9484cSchristos   *bufptr = 0;
8898b9484cSchristos   first_insn_p = first_p;
8998b9484cSchristos 
90212397c6Schristos   /* Set to NULL so cgen_trace_insn_fini can know if cgen_trace_insn was
91212397c6Schristos      called.  */
9298b9484cSchristos   current_insn = NULL;
9398b9484cSchristos   current_abuf = NULL;
9498b9484cSchristos }
9598b9484cSchristos 
9698b9484cSchristos void
97212397c6Schristos cgen_trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
9898b9484cSchristos {
9998b9484cSchristos   SIM_DESC sd = CPU_STATE (cpu);
10098b9484cSchristos 
10198b9484cSchristos   /* Was insn traced?  It might not be if trace ranges are in effect.  */
10298b9484cSchristos   if (current_insn == NULL)
10398b9484cSchristos     return;
10498b9484cSchristos 
10598b9484cSchristos   /* The first thing printed is current and total cycle counts.  */
10698b9484cSchristos 
10798b9484cSchristos   if (PROFILE_MODEL_P (cpu)
10898b9484cSchristos       && ARGBUF_PROFILE_P (current_abuf))
10998b9484cSchristos     {
11098b9484cSchristos       unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu));
11198b9484cSchristos       unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu));
11298b9484cSchristos 
11398b9484cSchristos       if (last_p)
11498b9484cSchristos 	{
11598b9484cSchristos 	  trace_printf (sd, cpu, "%-*ld %-*ld ",
11698b9484cSchristos 			SIZE_CYCLE_COUNT, this_insn,
11798b9484cSchristos 			SIZE_TOTAL_CYCLE_COUNT, total);
11898b9484cSchristos 	}
11998b9484cSchristos       else
12098b9484cSchristos 	{
12198b9484cSchristos 	  trace_printf (sd, cpu, "%-*ld %-*s ",
12298b9484cSchristos 			SIZE_CYCLE_COUNT, this_insn,
12398b9484cSchristos 			SIZE_TOTAL_CYCLE_COUNT, "---");
12498b9484cSchristos 	}
12598b9484cSchristos     }
12698b9484cSchristos 
12798b9484cSchristos   /* Print the disassembled insn.  */
12898b9484cSchristos 
12998b9484cSchristos   trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu)));
13098b9484cSchristos 
13198b9484cSchristos #if 0
13298b9484cSchristos   /* Print insn results.  */
13398b9484cSchristos   {
13498b9484cSchristos     const CGEN_OPINST *opinst = CGEN_INSN_OPERANDS (current_insn);
13598b9484cSchristos 
13698b9484cSchristos     if (opinst)
13798b9484cSchristos       {
13898b9484cSchristos 	int i;
13998b9484cSchristos 	int indices[MAX_OPERAND_INSTANCES];
14098b9484cSchristos 
14198b9484cSchristos 	/* Fetch the operands used by the insn.  */
14298b9484cSchristos 	/* FIXME: Add fn ptr to CGEN_CPU_DESC.  */
14398b9484cSchristos 	CGEN_SYM (get_insn_operands) (CPU_CPU_DESC (cpu), current_insn,
14498b9484cSchristos 				      0, CGEN_FIELDS_BITSIZE (&insn_fields),
14598b9484cSchristos 				      indices);
14698b9484cSchristos 
14798b9484cSchristos 	for (i = 0;
14898b9484cSchristos 	     CGEN_OPINST_TYPE (opinst) != CGEN_OPINST_END;
14998b9484cSchristos 	     ++i, ++opinst)
15098b9484cSchristos 	  {
15198b9484cSchristos 	    if (CGEN_OPINST_TYPE (opinst) == CGEN_OPINST_OUTPUT)
152212397c6Schristos 	      cgen_trace_result (cpu, current_insn, opinst, indices[i]);
15398b9484cSchristos 	  }
15498b9484cSchristos       }
15598b9484cSchristos   }
15698b9484cSchristos #endif
15798b9484cSchristos 
15898b9484cSchristos   /* Print anything else requested.  */
15998b9484cSchristos 
16098b9484cSchristos   if (*trace_buf)
16198b9484cSchristos     trace_printf (sd, cpu, " %s\n", trace_buf);
16298b9484cSchristos   else
16398b9484cSchristos     trace_printf (sd, cpu, "\n");
16498b9484cSchristos }
16598b9484cSchristos 
16698b9484cSchristos void
167212397c6Schristos cgen_trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
16898b9484cSchristos 		 const struct argbuf *abuf, IADDR pc)
16998b9484cSchristos {
17098b9484cSchristos   char disasm_buf[50];
17198b9484cSchristos 
17298b9484cSchristos   printed_result_p = 0;
17398b9484cSchristos   current_insn = opcode;
17498b9484cSchristos   current_abuf = abuf;
17598b9484cSchristos 
17698b9484cSchristos   if (CGEN_INSN_VIRTUAL_P (opcode))
17798b9484cSchristos     {
17898b9484cSchristos       trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, 0,
1794b169a6bSchristos 		    NULL, 0, "%s", CGEN_INSN_NAME (opcode));
18098b9484cSchristos       return;
18198b9484cSchristos     }
18298b9484cSchristos 
18398b9484cSchristos   CPU_DISASSEMBLER (cpu) (cpu, opcode, abuf, pc, disasm_buf);
18498b9484cSchristos   trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
18598b9484cSchristos 		NULL, 0,
18698b9484cSchristos 		"%s%-*s",
18798b9484cSchristos 		first_insn_p ? " " : "|",
18898b9484cSchristos 		SIZE_INSTRUCTION, disasm_buf);
18998b9484cSchristos }
19098b9484cSchristos 
19198b9484cSchristos void
1924b169a6bSchristos cgen_trace_extract (SIM_CPU *cpu, IADDR pc, const char *name, ...)
19398b9484cSchristos {
19498b9484cSchristos   va_list args;
19598b9484cSchristos   int printed_one_p = 0;
1964b169a6bSchristos   const char *fmt;
19798b9484cSchristos 
19898b9484cSchristos   va_start (args, name);
19998b9484cSchristos 
20098b9484cSchristos   trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ",
20198b9484cSchristos 		SIZE_PC, (unsigned long) pc, name);
20298b9484cSchristos 
20398b9484cSchristos   do {
20498b9484cSchristos     int type,ival;
20598b9484cSchristos 
2064b169a6bSchristos     fmt = va_arg (args, const char *);
20798b9484cSchristos 
20898b9484cSchristos     if (fmt)
20998b9484cSchristos       {
21098b9484cSchristos 	if (printed_one_p)
21198b9484cSchristos 	  trace_printf (CPU_STATE (cpu), cpu, ", ");
21298b9484cSchristos 	printed_one_p = 1;
21398b9484cSchristos 	type = va_arg (args, int);
21498b9484cSchristos 	switch (type)
21598b9484cSchristos 	  {
21698b9484cSchristos 	  case 'x' :
21798b9484cSchristos 	    ival = va_arg (args, int);
2184b169a6bSchristos 	    DIAGNOSTIC_PUSH
2194b169a6bSchristos 	    DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
22098b9484cSchristos 	    trace_printf (CPU_STATE (cpu), cpu, fmt, ival);
2214b169a6bSchristos 	    DIAGNOSTIC_POP
22298b9484cSchristos 	    break;
22398b9484cSchristos 	  default :
22498b9484cSchristos 	    abort ();
22598b9484cSchristos 	  }
22698b9484cSchristos       }
22798b9484cSchristos   } while (fmt);
22898b9484cSchristos 
22998b9484cSchristos   va_end (args);
23098b9484cSchristos   trace_printf (CPU_STATE (cpu), cpu, "\n");
23198b9484cSchristos }
23298b9484cSchristos 
23398b9484cSchristos void
2344b169a6bSchristos cgen_trace_result (SIM_CPU *cpu, const char *name, int type, ...)
23598b9484cSchristos {
23698b9484cSchristos   va_list args;
23798b9484cSchristos 
23898b9484cSchristos   va_start (args, type);
23998b9484cSchristos   if (printed_result_p)
24098b9484cSchristos     cgen_trace_printf (cpu, ", ");
24198b9484cSchristos 
24298b9484cSchristos   switch (type)
24398b9484cSchristos     {
24498b9484cSchristos     case 'x' :
24598b9484cSchristos     default :
24698b9484cSchristos       cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int));
24798b9484cSchristos       break;
24898b9484cSchristos     case 'f':
24998b9484cSchristos       {
25098b9484cSchristos 	DI di;
25198b9484cSchristos 	sim_fpu f;
25298b9484cSchristos 
25398b9484cSchristos 	/* this is separated from previous line for sunos cc */
25498b9484cSchristos 	di = va_arg (args, DI);
25598b9484cSchristos 	sim_fpu_64to (&f, di);
25698b9484cSchristos 
25798b9484cSchristos 	cgen_trace_printf (cpu, "%s <- ", name);
25898b9484cSchristos 	sim_fpu_printn_fpu (&f, (sim_fpu_print_func *) cgen_trace_printf, 4, cpu);
25998b9484cSchristos 	break;
26098b9484cSchristos       }
26198b9484cSchristos     case 'D' :
26298b9484cSchristos       {
26398b9484cSchristos 	DI di;
26498b9484cSchristos 	/* this is separated from previous line for sunos cc */
26598b9484cSchristos 	di = va_arg (args, DI);
26698b9484cSchristos 	cgen_trace_printf (cpu, "%s <- 0x%x%08x", name,
26798b9484cSchristos 			   GETHIDI(di), GETLODI (di));
26898b9484cSchristos 	break;
26998b9484cSchristos       }
27098b9484cSchristos     }
27198b9484cSchristos 
27298b9484cSchristos   printed_result_p = 1;
27398b9484cSchristos   va_end (args);
27498b9484cSchristos }
27598b9484cSchristos 
27698b9484cSchristos /* Print trace output to BUFPTR if active, otherwise print normally.
27798b9484cSchristos    This is only for tracing semantic code.  */
27898b9484cSchristos 
27998b9484cSchristos void
2804b169a6bSchristos cgen_trace_printf (SIM_CPU *cpu, const char *fmt, ...)
28198b9484cSchristos {
28298b9484cSchristos   va_list args;
28398b9484cSchristos 
28498b9484cSchristos   va_start (args, fmt);
28598b9484cSchristos 
28698b9484cSchristos   if (bufptr == NULL)
28798b9484cSchristos     {
28898b9484cSchristos       if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL)
28998b9484cSchristos 	(* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
29098b9484cSchristos 	  (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args);
29198b9484cSchristos       else
29298b9484cSchristos 	vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args);
29398b9484cSchristos     }
29498b9484cSchristos   else
29598b9484cSchristos     {
29698b9484cSchristos       vsprintf (bufptr, fmt, args);
29798b9484cSchristos       bufptr += strlen (bufptr);
29898b9484cSchristos       /* ??? Need version of SIM_ASSERT that is always enabled.  */
29998b9484cSchristos       if (bufptr - trace_buf > SIZE_TRACE_BUF)
30098b9484cSchristos 	abort ();
30198b9484cSchristos     }
30298b9484cSchristos 
30398b9484cSchristos   va_end (args);
30498b9484cSchristos }
30598b9484cSchristos 
30698b9484cSchristos /* Disassembly support.  */
30798b9484cSchristos 
30898b9484cSchristos /* sprintf to a "stream" */
30998b9484cSchristos 
31098b9484cSchristos int
31103467a24Schristos sim_disasm_sprintf (SFILE *f, const char *format, ...)
31298b9484cSchristos {
31398b9484cSchristos   int n;
31498b9484cSchristos   va_list args;
31598b9484cSchristos 
31603467a24Schristos   va_start (args, format);
31798b9484cSchristos   vsprintf (f->current, format, args);
31898b9484cSchristos   f->current += n = strlen (f->current);
31998b9484cSchristos   va_end (args);
32098b9484cSchristos   return n;
32198b9484cSchristos }
32298b9484cSchristos 
3234b169a6bSchristos /* sprintf to a "stream" with styling.  */
3244b169a6bSchristos 
3254b169a6bSchristos int
3264b169a6bSchristos sim_disasm_styled_sprintf (SFILE *f, enum disassembler_style style,
3274b169a6bSchristos 			   const char *format, ...)
3284b169a6bSchristos {
3294b169a6bSchristos   int n;
3304b169a6bSchristos   va_list args;
3314b169a6bSchristos 
3324b169a6bSchristos   va_start (args, format);
3334b169a6bSchristos   vsprintf (f->current, format, args);
3344b169a6bSchristos   f->current += n = strlen (f->current);
3354b169a6bSchristos   va_end (args);
3364b169a6bSchristos   return n;
3374b169a6bSchristos }
3384b169a6bSchristos 
33998b9484cSchristos /* Memory read support for an opcodes disassembler.  */
34098b9484cSchristos 
34198b9484cSchristos int
34298b9484cSchristos sim_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
34398b9484cSchristos 			struct disassemble_info *info)
34498b9484cSchristos {
34598b9484cSchristos   SIM_CPU *cpu = (SIM_CPU *) info->application_data;
34698b9484cSchristos   SIM_DESC sd = CPU_STATE (cpu);
34798b9484cSchristos   unsigned length_read;
34898b9484cSchristos 
34998b9484cSchristos   length_read = sim_core_read_buffer (sd, cpu, read_map, myaddr, memaddr,
35098b9484cSchristos 				      length);
35198b9484cSchristos   if (length_read != length)
35298b9484cSchristos     return EIO;
35398b9484cSchristos   return 0;
35498b9484cSchristos }
35598b9484cSchristos 
35698b9484cSchristos /* Memory error support for an opcodes disassembler.  */
35798b9484cSchristos 
35898b9484cSchristos void
35998b9484cSchristos sim_disasm_perror_memory (int status, bfd_vma memaddr,
36098b9484cSchristos 			  struct disassemble_info *info)
36198b9484cSchristos {
36298b9484cSchristos   if (status != EIO)
36398b9484cSchristos     /* Can't happen.  */
36498b9484cSchristos     info->fprintf_func (info->stream, "Unknown error %d.", status);
36598b9484cSchristos   else
36698b9484cSchristos     /* Actually, address between memaddr and memaddr + len was
36798b9484cSchristos        out of bounds.  */
36898b9484cSchristos     info->fprintf_func (info->stream,
3694b169a6bSchristos 			"Address 0x%" PRIx64 " is out of bounds.",
3704b169a6bSchristos 			(uint64_t) memaddr);
37198b9484cSchristos }
37298b9484cSchristos 
37398b9484cSchristos /* Disassemble using the CGEN opcode table.
37498b9484cSchristos    ??? While executing an instruction, the insn has been decoded and all its
37598b9484cSchristos    fields have been extracted.  It is certainly possible to do the disassembly
37698b9484cSchristos    with that data.  This seems simpler, but maybe in the future the already
37798b9484cSchristos    extracted fields will be used.  */
37898b9484cSchristos 
37998b9484cSchristos void
38098b9484cSchristos sim_cgen_disassemble_insn (SIM_CPU *cpu, const CGEN_INSN *insn,
38198b9484cSchristos 			   const ARGBUF *abuf, IADDR pc, char *buf)
38298b9484cSchristos {
38398b9484cSchristos   unsigned int length;
38498b9484cSchristos   unsigned int base_length;
38598b9484cSchristos   unsigned long insn_value;
38698b9484cSchristos   struct disassemble_info disasm_info;
38798b9484cSchristos   SFILE sfile;
38898b9484cSchristos   union {
3894b169a6bSchristos     uint8_t bytes[CGEN_MAX_INSN_SIZE];
3904b169a6bSchristos     uint16_t shorts[8];
3914b169a6bSchristos     uint32_t words[4];
39298b9484cSchristos   } insn_buf;
39398b9484cSchristos   SIM_DESC sd = CPU_STATE (cpu);
39498b9484cSchristos   CGEN_CPU_DESC cd = CPU_CPU_DESC (cpu);
39598b9484cSchristos   CGEN_EXTRACT_INFO ex_info;
39698b9484cSchristos   CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
39798b9484cSchristos   int insn_bit_length = CGEN_INSN_BITSIZE (insn);
39898b9484cSchristos   int insn_length = insn_bit_length / 8;
39998b9484cSchristos 
40098b9484cSchristos   sfile.buffer = sfile.current = buf;
40198b9484cSchristos   INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile,
4024b169a6bSchristos 			 (fprintf_ftype) sim_disasm_sprintf,
4034b169a6bSchristos 			 (fprintf_styled_ftype) sim_disasm_styled_sprintf);
40498b9484cSchristos   disasm_info.endian =
40598b9484cSchristos     (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG
40698b9484cSchristos      : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE
40798b9484cSchristos      : BFD_ENDIAN_UNKNOWN);
40898b9484cSchristos 
40998b9484cSchristos   length = sim_core_read_buffer (sd, cpu, read_map, &insn_buf, pc,
41098b9484cSchristos 				 insn_length);
41198b9484cSchristos 
41298b9484cSchristos   if (length != insn_length)
41398b9484cSchristos   {
4144b169a6bSchristos     sim_io_error (sd, "unable to read address %" PRIxTA, pc);
41598b9484cSchristos   }
41698b9484cSchristos 
41798b9484cSchristos   /* If the entire insn will fit into an integer, then do it. Otherwise, just
41898b9484cSchristos      use the bits of the base_insn.  */
41998b9484cSchristos   if (insn_bit_length <= 32)
42098b9484cSchristos     base_length = insn_bit_length;
42198b9484cSchristos   else
42298b9484cSchristos     base_length = min (cd->base_insn_bitsize, insn_bit_length);
42398b9484cSchristos   switch (base_length)
42498b9484cSchristos     {
42598b9484cSchristos     case 0 : return; /* fake insn, typically "compile" (aka "invalid") */
42698b9484cSchristos     case 8 : insn_value = insn_buf.bytes[0]; break;
42798b9484cSchristos     case 16 : insn_value = T2H_2 (insn_buf.shorts[0]); break;
42898b9484cSchristos     case 32 : insn_value = T2H_4 (insn_buf.words[0]); break;
42998b9484cSchristos     default: abort ();
43098b9484cSchristos     }
43198b9484cSchristos 
43298b9484cSchristos   disasm_info.buffer_vma = pc;
43398b9484cSchristos   disasm_info.buffer = insn_buf.bytes;
43498b9484cSchristos   disasm_info.buffer_length = length;
43598b9484cSchristos 
4364b169a6bSchristos   ex_info.dis_info = &disasm_info;
43798b9484cSchristos   ex_info.valid = (1 << length) - 1;
43898b9484cSchristos   ex_info.insn_bytes = insn_buf.bytes;
43998b9484cSchristos 
44098b9484cSchristos   length = (*CGEN_EXTRACT_FN (cd, insn)) (cd, insn, &ex_info, insn_value, fields, pc);
44198b9484cSchristos   /* Result of extract fn is in bits.  */
44298b9484cSchristos   /* ??? This assumes that each instruction has a fixed length (and thus
44398b9484cSchristos      for insns with multiple versions of variable lengths they would each
44498b9484cSchristos      have their own table entry).  */
44598b9484cSchristos   if (length == insn_bit_length)
44698b9484cSchristos     {
44798b9484cSchristos       (*CGEN_PRINT_FN (cd, insn)) (cd, &disasm_info, insn, fields, pc, length);
44898b9484cSchristos     }
44998b9484cSchristos   else
45098b9484cSchristos     {
45198b9484cSchristos       /* This shouldn't happen, but aborting is too drastic.  */
45298b9484cSchristos       strcpy (buf, "***unknown***");
45398b9484cSchristos     }
45498b9484cSchristos }
455