This is the mail archive of the cgen@sources.redhat.com mailing list for the CGEN project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[RFA] Provide cgen_disn and cgen_fields in disassemble_info


I posted this patch to binutils some days ago, but I've since been
informed that this is the preferred forum for posting cgen-related opcodes
patches.

The appended patch introduces two new fields to struct disassemble_info:

  struct cgen_insn *cgen_insn;	/* If non-null, pointer to CGEN_INSN
				   instruction descriptor.  */
  struct cgen_fields *cgen_fields; /* If caller sets to non-null, receives
				   CGEN_FIELDS operand descriptor.  */

After print_insn_@arch@ completes successfuly, those fields contain
information about the instruction printed.

The patch also adds a new function, decode_insn_@arch@, which doesn't
print any output but otherwise is identical to print_insn_@arch@.

I've found this useful for parsing prologue and other instructions in GDB.
I find it easier and more maintainable than the usual approach of
peppering GDB skip_prologue() functions with hard-coded bit offsets and
lengths.

Comments?  Okay to apply?

opcodes/ChangeLog:

	* cgen-dis.in (decode_insn, default_decode_insn, decode_init,
	decode_insn_@arch@): New functions.
	(print_insn): Mostly move into decode_insn().
	(CGEN_DECODE_INSN): Define.
	(print_insn_@arch@): Mostly move into decode_init().

include/ChangeLog:

	* dis-asm.h (struct disassemble_info): Add cgen_insn and
	cgen_fields fields.

Nick Duffek
<nsd@redhat.com>

[patch follows]

Index: include/dis-asm.h
===================================================================
diff -up include/dis-asm.h include/dis-asm.h
--- include/dis-asm.h	Mon Jul 16 14:24:47 2001
+++ include/dis-asm.h	Mon Jul 16 14:24:39 2001
@@ -47,6 +47,11 @@ enum dis_insn_type {
   dis_dref2			/* Two data references in instruction */
 };
 
+/* Forward declarations.  */
+
+struct cgen_insn;
+struct cgen_fields;
+
 /* This struct is passed into the instruction decoding routine, 
    and is passed back out into each callback.  The various fields are used
    for conveying information from your main routine into your callbacks,
@@ -164,6 +169,13 @@ typedef struct disassemble_info {
   bfd_vma target;		/* Target address of branch or dref, if known;
 				   zero if unknown.  */
   bfd_vma target2;		/* Second target address for dref2 */
+
+  /* Results from CGEN instruction decoders.  */
+
+  struct cgen_insn *cgen_insn;	/* If non-null, pointer to CGEN_INSN
+				   instruction descriptor.  */
+  struct cgen_fields *cgen_fields; /* If caller sets to non-null, receives
+				   CGEN_FIELDS operand descriptor.  */
 
   /* Command line options specific to the target disassembler.  */
   char * disassembler_options;
Index: opcodes/cgen-dis.in
===================================================================
diff -up opcodes/cgen-dis.in opcodes/cgen-dis.in
--- opcodes/cgen-dis.in	Mon Jul 16 14:24:49 2001
+++ opcodes/cgen-dis.in	Mon Jul 16 12:24:05 2001
@@ -47,10 +47,15 @@ static void print_keyword
 static void print_insn_normal
      PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
 	      bfd_vma, int));
-static int print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma,
-			       disassemble_info *, char *, int));
+static int decode_insn PARAMS ((CGEN_CPU_DESC, bfd_vma,
+				disassemble_info *, char *, int,
+				CGEN_FIELDS *));
+static int default_decode_insn
+     PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, CGEN_FIELDS *));
 static int default_print_insn
      PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
+static CGEN_CPU_DESC decode_init
+     PARAMS ((disassemble_info *));
 
 /* -- disassembler routines inserted here */
 
@@ -187,7 +192,7 @@ print_insn_normal (cd, dis_info, insn, f
     }
 }
 
-/* Subroutine of print_insn. Reads an insn into the given buffers and updates
+/* Subroutine of decode_insn. Reads an insn into the given buffers and updates
    the extract info.
    Returns 0 if all is well, non-zero otherwise.  */
 static int
@@ -215,19 +220,23 @@ read_insn (cd, pc, info, buf, buflen, ex
   return 0;
 }
 
-/* Utility to print an insn.
+/* Utility to decode an insn.
+
    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    The result is the size of the insn in bytes or zero for an unknown insn
    or -1 if an error occurs fetching data (memory_error_func will have
-   been called).  */
+   been called).
+
+   FIELDS points to storage for the insn's extracted fields.  */
 
 static int
-print_insn (cd, pc, info, buf, buflen)
+decode_insn (cd, pc, info, buf, buflen, fields)
      CGEN_CPU_DESC cd;
      bfd_vma pc;
      disassemble_info *info;
      char *buf;
      int buflen;
+     CGEN_FIELDS *fields;
 {
   CGEN_INSN_INT insn_value;
   const CGEN_INSN_LIST *insn_list;
@@ -250,7 +259,6 @@ print_insn (cd, pc, info, buf, buflen)
   while (insn_list != NULL)
     {
       const CGEN_INSN *insn = insn_list->insn;
-      CGEN_FIELDS fields;
       int length;
       unsigned long insn_value_cropped;
 
@@ -296,18 +304,18 @@ print_insn (cd, pc, info, buf, buflen)
 	      if (rc != 0)
 		return rc;
 	      length = CGEN_EXTRACT_FN (cd, insn)
-		(cd, insn, &ex_info, full_insn_value, &fields, pc);
+		(cd, insn, &ex_info, full_insn_value, fields, pc);
 	    }
 	  else
 	    length = CGEN_EXTRACT_FN (cd, insn)
-	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
+	      (cd, insn, &ex_info, insn_value_cropped, fields, pc);
 
 	  /* length < 0 -> error */
 	  if (length < 0)
 	    return length;
 	  if (length > 0)
 	    {
-	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
+	      info->cgen_insn = (void *) insn;
 	      /* length is in bits, result is in bytes */
 	      return length / 8;
 	    }
@@ -319,19 +327,20 @@ print_insn (cd, pc, info, buf, buflen)
   return 0;
 }
 
-/* Default value for CGEN_PRINT_INSN.
+/* Default value for CGEN_DECODE_INSN.
    The result is the size of the insn in bytes or zero for an unknown insn
    or -1 if an error occured fetching bytes.  */
 
-#ifndef CGEN_PRINT_INSN
-#define CGEN_PRINT_INSN default_print_insn
+#ifndef CGEN_DECODE_INSN
+#define CGEN_DECODE_INSN default_decode_insn
 #endif
 
 static int
-default_print_insn (cd, pc, info)
+default_decode_insn (cd, pc, info, fields)
      CGEN_CPU_DESC cd;
      bfd_vma pc;
      disassemble_info *info;
+     CGEN_FIELDS *fields;
 {
   char buf[CGEN_MAX_INSN_SIZE];
   int buflen;
@@ -354,23 +363,46 @@ default_print_insn (cd, pc, info)
       return -1;
     }
 
-  return print_insn (cd, pc, info, buf, buflen);
+  return decode_insn (cd, pc, info, buf, buflen, fields);
 }
 
-/* Main entry point.
-   Print one instruction from PC on INFO->STREAM.
-   Return the size of the instruction (in bytes).  */
+/* Default value for CGEN_PRINT_INSN.
+   The result is the size of the insn in bytes or zero for an unknown insn
+   or -1 if an error occured fetching bytes.  */
 
-int
-print_insn_@arch@ (pc, info)
+#ifndef CGEN_PRINT_INSN
+#define CGEN_PRINT_INSN default_print_insn
+#endif
+
+static int
+default_print_insn (cd, pc, info)
+     CGEN_CPU_DESC cd;
      bfd_vma pc;
      disassemble_info *info;
 {
+  CGEN_FIELDS fields;
+  int length;
+  const CGEN_INSN *insn;
+
+  length = CGEN_DECODE_INSN (cd, pc, info, &fields);
+  if (length > 0)
+    {
+      insn = info->cgen_insn;
+      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length * 8);
+    }
+  return length ;
+}
+
+/* Prepare to decode the instruction at PC.  */
+
+static CGEN_CPU_DESC
+decode_init (info)
+     disassemble_info *info;
+{
   static CGEN_CPU_DESC cd = 0;
   static int prev_isa;
   static int prev_mach;
   static int prev_endian;
-  int length;
   int isa,mach;
   int endian = (info->endian == BFD_ENDIAN_BIG
 		? CGEN_ENDIAN_BIG
@@ -430,6 +462,43 @@ print_insn_@arch@ (pc, info)
 	abort ();
       @arch@_cgen_init_dis (cd);
     }
+
+  return cd;
+}
+
+/* Main entry point for decoding.
+   Store in INFO information about the instruction at PC.
+   If successful, return the size of the instruction (in bytes).  Otherwise,
+   return 0 for an unknown insn and -1 if some other error occurred.  */
+
+int
+decode_insn_@arch@ (pc, info)
+     bfd_vma pc;
+     disassemble_info *info;
+{
+  CGEN_CPU_DESC cd = decode_init (info);
+
+  /* We try to have as much common code as possible.
+     But at this point some targets need to take over.  */
+  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
+     but if not possible try to move this hook elsewhere rather than
+     have two hooks.  */
+  return CGEN_DECODE_INSN (cd, pc, info, info->cgen_fields);
+}
+
+/* Main entry point for printing.
+   Print one instruction from PC on INFO->STREAM.
+   Return the size of the instruction (in bytes).  */
+
+int
+print_insn_@arch@ (pc, info)
+     bfd_vma pc;
+     disassemble_info *info;
+{
+  CGEN_CPU_DESC cd;
+  int length;
+
+  cd = decode_init (info);
 
   /* We try to have as much common code as possible.
      But at this point some targets need to take over.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]