This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] communicate instruction type to disasm callback


Similar to what the BFD interface does, these changes introduce a way to
pass additional information to the callback function provided in the
disasm_cb call.

This is an ABI break but I'm pretty sure that I am the only person who
ever used the interface and the only public user is objdump which is
also changed.  There is no user, yet, but this information is clearly
needed for some use cases.

If someone disagrees I have no problem with bumping the SONAME of
libasm.


Someone please commit the change.


libasm/Changelog

2014-12-18  Ulrich Drepper  <drepper@gmail.com>

	* libasm.h (DisasmOutputCB_t): Add new parameter for flags.
        Define constants to be used for the flag parameter.
	* disasm_str.c (buffer_cb): Add new parameter and don't use it.


libcpu/ChangeLog

2014-12-18  Ulrich Drepper  <drepper@gmail.com>

	* defs/i386: Add instruction type information to call, branch,
        and return instructions.
        * i386_lex.l: Recognize ';' token.
        * i386_parse.y: Recognize optional instruction type field and
        emit the instruction type information.
        * i386_disasm.c (i386_disasm): Use new .type field from
        instruction table to fill flag parameter of callback.
        * Makefile.am: Adjust %.mnemonics rule for changes in the input
        file format.

src/ChangeLog

2014-12-18  Ulrich Drepper  <drepper@gmail.com>

	* objdump.c (disasm_output): Add new parameter and ignore it
        for now.


diff --git a/libasm/disasm_str.c b/libasm/disasm_str.c
index 5b0bb29..36adb4e 100644
--- a/libasm/disasm_str.c
+++ b/libasm/disasm_str.c
@@ -43,7 +43,8 @@ struct buffer
 
 
 static int
-buffer_cb (char *str, size_t len, void *arg)
+buffer_cb (char *str, size_t len, void *arg,
+	   uint64_t flags __attribute__ ((unused)))
 {
   struct buffer *buffer = (struct buffer *) arg;
 
diff --git a/libasm/libasm.h b/libasm/libasm.h
index 5c61224..173a1c8 100644
--- a/libasm/libasm.h
+++ b/libasm/libasm.h
@@ -58,8 +58,18 @@ typedef struct DisasmCtx DisasmCtx_t;
 typedef int (*DisasmGetSymCB_t) (GElf_Addr, Elf32_Word, GElf_Addr, char **,
 				 size_t *, void *);
 
+/* Values for the flag argument of DISASMOUTPUTCB_T callbacks.  */
+enum {
+  DISASM_INSTRTYPE_MASK = UINT64_C (0xf),
+  DISASM_INSTRTYPE_NOINFO = UINT64_C (0x0),
+  DISASM_INSTRTYPE_CALL = UINT64_C (0x1),
+  DISASM_INSTRTYPE_BRANCH = UINT64_C (0x2),
+  DISASM_INSTRTYPE_CONDBRANCH = UINT64_C (0x3),
+  DISASM_INSTRTYPE_RETURN = UINT64_C (0x4),
+};
+
 /* Output function callback.  */
-typedef int (*DisasmOutputCB_t) (char *, size_t, void *);
+typedef int (*DisasmOutputCB_t) (char *, size_t, void *, uint64_t);
 
 
 #ifdef __cplusplus
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index 3beccf3..6ecaee6 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -67,7 +67,7 @@ $(srcdir)/%_dis.h:
 endif
 
 %.mnemonics: %_defs
-	sed '1,/^%%/d;/^#/d;/^[[:space:]]*$$/d;s/[^:]*:\([^[:space:]]*\).*/MNE(\1)/;s/{[^}]*}//g;/INVALID/d' \
+	sed '1,/^%%/d;/^#/d;/^[[:space:]]*$$/d;s/[^:]*:\([^[:space:];]*\).*/MNE(\1)/;s/{[^}]*}//g;/INVALID/d' \
 	  $< | sort -u > $@
 
 i386_lex_no_Werror = yes
diff --git a/libcpu/defs/i386 b/libcpu/defs/i386
index e0db28d..d1b3a25 100644
--- a/libcpu/defs/i386
+++ b/libcpu/defs/i386
@@ -63,6 +63,13 @@ ifdef(`i386',
 %synonym {imm64} {imm}
 ')dnl
 
+dnl Instruction type (last field after mnemonic)
+dnl B - branch
+dnl C - conditional branch
+dnl S - subroutine call
+dnl R - return from subroutine
+dnl M - memory reference
+
 %%
 ifdef(`i386',
 `00110111:aaa
@@ -108,12 +115,12 @@ ifdef(`i386',
 00001111,10111010,{mod}110{r_m},{imm8}:btr{w} {imm8},{mod}{r_m}
 00001111,10101011,{mod}{reg}{r_m}:bts {reg},{mod}{r_m}
 00001111,10111010,{mod}101{r_m},{imm8}:bts{w} {imm8},{mod}{r_m}
-11101000,{rel}:call{W} {rel}
-11111111,{mod}010{64r_m}:call{W} *{mod}{64r_m}
+11101000,{rel}:call{W} {rel};S
+11111111,{mod}010{64r_m}:call{W} *{mod}{64r_m};S
 ifdef(`i386',
-`10011010,{absval},{sel}:lcall {sel},{absval}
+`10011010,{absval},{sel}:lcall {sel},{absval};S
 ')dnl
-11111111,{mod}011{64r_m}:lcall{W} *{mod}{64r_m}
+11111111,{mod}011{64r_m}:lcall{W} *{mod}{64r_m};S
 # SPECIAL 10011000:[{rex.w}?cltq:{dpfx}?cbtw:cwtl]
 10011000:INVALID
 # SPECIAL 10011001:[{rex.w}?cqto:{dpfx}?cltd:cwtd]
@@ -372,17 +379,17 @@ ifdef(`i386',
 00001111,00000001,11111000:swapgs
 00001111,00000001,{mod}111{r_m}:invlpg {mod}{r_m}
 # ORDER END
-11001111:iret{W1}
-0111{tttn},{disp8}:j{tttn} {disp8}
-00001111,1000{tttn},{rel}:j{tttn} {rel}
+11001111:iret{W1};R
+0111{tttn},{disp8}:j{tttn} {disp8};C
+00001111,1000{tttn},{rel}:j{tttn} {rel};C
 00001111,1001{tttn},{mod}000{8r_m}:set{tttn} {mod}{8r_m}
-# SPECIAL 11100011,{disp8}:[{dpfx}?jcxz:jecxz] {disp8}
+# SPECIAL 11100011,{disp8}:[{dpfx}?jcxz:jecxz] {disp8};C
 11100011,{disp8}:INVALID {disp8}
-11101011,{disp8}:jmp {disp8}
-11101001,{rel}:jmp{W} {rel}
-11111111,{mod}100{64r_m}:jmp{W} *{mod}{64r_m}
-11101010,{absval},{sel}:ljmp {sel},{absval}
-11111111,{mod}101{64r_m}:ljmp{W} *{mod}{64r_m}
+11101011,{disp8}:jmp {disp8};B
+11101001,{rel}:jmp{W} {rel};B
+11111111,{mod}100{64r_m}:jmp{W} *{mod}{64r_m};B
+11101010,{absval},{sel}:ljmp {sel},{absval};B
+11111111,{mod}101{64r_m}:ljmp{W} *{mod}{64r_m};B
 10011111:lahf
 00001111,00000010,{mod}{reg}{16r_m}:lar {mod}{16r_m},{reg}
 ifdef(`i386',
@@ -406,9 +413,9 @@ ifdef(`i386',
 00001111,00000001,{mod}110{16r_m}:lmsw {mod}{16r_m}
 11110000:lock
 1010110{w}:{R}lods {ds_si},{ax}{w}
-11100010,{disp8}:loop {disp8}
-11100001,{disp8}:loope {disp8}
-11100000,{disp8}:loopne {disp8}
+11100010,{disp8}:loop {disp8};C
+11100001,{disp8}:loope {disp8};C
+11100000,{disp8}:loopne {disp8};C
 00001111,00000011,{mod}{reg}{16r_m}:lsl {mod}{16r_m},{reg}
 00001111,10110010,{mod}{reg}{r_m}:lss {mod}{r_m},{reg}
 00001111,00000000,{mod}011{16r_m}:ltr {mod}{16r_m}
@@ -489,10 +496,10 @@ ifdef(`i386',
 00001111,00110010:rdmsr
 00001111,00110011:rdpmc
 00001111,00110001:rdtsc
-11000011:ret{W}
-11000010,{imm16}:ret{W} {imm16}
-11001011:lret
-11001010,{imm16}:lret {imm16}
+11000011:ret{W};R
+11000010,{imm16}:ret{W} {imm16};R
+11001011:lret;R
+11001010,{imm16}:lret {imm16};R
 1101000{w},{mod}000{r_m}:rol{w} {mod}{r_m}{w}
 1101001{w},{mod}000{r_m}:rol{w} %cl,{mod}{r_m}{w}
 1100000{w},{mod}000{r_m},{imm8}:rol{w} {imm8},{mod}{r_m}{w}
diff --git a/libcpu/i386_data.h b/libcpu/i386_data.h
index b8a34c3..4f7e601 100644
--- a/libcpu/i386_data.h
+++ b/libcpu/i386_data.h
@@ -78,6 +78,7 @@ struct instr_enc
 #ifdef OFF3_3_BITS
   unsigned int off3_3 : OFF3_3_BITS;
 #endif
+  unsigned int type : TYPE_BITS;
 };
 
 
diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c
index 832241f..4e74e70 100644
--- a/libcpu/i386_disasm.c
+++ b/libcpu/i386_disasm.c
@@ -1134,8 +1134,26 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
 	goto enomem;
       buf[bufcnt] = '\0';
 
+      /* Build up the flags argument.  */
+      uint64_t flags = 0;
+      switch (instrtab[cnt].type)
+	{
+	case TYPE_B:
+	  flags |= DISASM_INSTRTYPE_BRANCH;
+	  break;
+	case TYPE_C:
+	  flags |= DISASM_INSTRTYPE_CONDBRANCH;
+	  break;
+	case TYPE_R:
+	  flags |= DISASM_INSTRTYPE_RETURN;
+	  break;
+	case TYPE_S:
+	  flags |= DISASM_INSTRTYPE_CALL;
+	  break;
+	}
+
       *startp = data;
-      retval = outcb (buf, bufcnt, outcbarg);
+      retval = outcb (buf, bufcnt, outcbarg, flags);
       if (retval != 0)
 	goto do_ret;
     }
diff --git a/libcpu/i386_lex.l b/libcpu/i386_lex.l
index 1e10dd7..8e97b24 100644
--- a/libcpu/i386_lex.l
+++ b/libcpu/i386_lex.l
@@ -86,6 +86,8 @@ WHITE		[[:space:]]+
 
 <MAIN>":"			{ return ':'; }
 
+<MAIN>";"			{ return ';'; }
+
 <INITIAL,MAIN>^"\n"		{ /* IGNORE */ }
 
 <INITIAL,MAIN>"\n"		{ return '\n'; }
diff --git a/libcpu/i386_parse.y b/libcpu/i386_parse.y
index 689ba22..c4867fd 100644
--- a/libcpu/i386_parse.y
+++ b/libcpu/i386_parse.y
@@ -79,6 +79,13 @@ struct bitvalue
 };
 
 
+struct instruction_type
+{
+  char *name;
+  unsigned long int value;
+};
+
+
 struct argname
 {
   enum nametype { string, nfield } type;
@@ -127,6 +134,9 @@ struct instruction
     int off3;
   } operands[3];
 
+  /* Instruction type.  */
+  unsigned long int type;
+
   struct instruction *next;
 };
 
@@ -193,6 +203,7 @@ static void fillin_arg (struct bitvalue *bytes, struct argname *name,
 static void find_numbers (void);
 static int compare_syn (const void *p1, const void *p2);
 static int compare_suf (const void *p1, const void *p2);
+static int type_compare (const void *p1, const void *p2);
 static void instrtable_out (void);
 #if 0
 static void create_mnemonic_table (void);
@@ -206,6 +217,8 @@ static void *suffixes;
 static int nsuffixes;
 static void *mnemonics;
 size_t nmnemonics;
+static unsigned long int typecnt = 1;
+static void *types;
 extern FILE *outfile;
 
 /* Number of bits used mnemonics.  */
@@ -239,6 +252,7 @@ static size_t best_mnemonic_bits;
 %type <field> bitfieldopt
 %type <name> argcomp arg
 %type <arg> args optargs
+%type <num> optinstrtype
 
 %defines
 
@@ -283,7 +297,7 @@ instrs:		  instrs '\n' instr
 		| instr
 		;
 
-instr:		  bytes ':' bitfieldopt kID bitfieldopt optargs
+instr:		  bytes ':' bitfieldopt kID bitfieldopt optargs optinstrtype
 		    {
 		      if ($3 != NULL && strcmp ($3->name, "RE") != 0
 			  && strcmp ($3->name, "R") != 0)
@@ -361,6 +375,8 @@ instr:		  bytes ':' bitfieldopt kID bitfieldopt optargs
 			      ++n;
 			    }
 
+			  newp->type = $7;
+
 			  newp->next = instructions;
 			  instructions = newp;
 			  ++ninstructions;
@@ -547,6 +563,32 @@ argcomp:	  kBITFIELD
 		    }
 		;
 
+optinstrtype:	';' kID
+		    {
+		      struct instruction_type search;
+		      search.name = $2;
+		      struct instruction_type **found;
+		      found = tfind (&search, &types, type_compare);
+		      if (found != NULL)
+			$$ = (*found)->value;
+		      else
+			{
+			   struct instruction_type *newp =
+			     xmalloc (sizeof (*newp));
+			   newp->name = xstrdup ($2);
+			   newp->value = typecnt++;
+			   if (tsearch (newp, &types,
+					type_compare) == NULL)
+			     error (EXIT_FAILURE, errno, "tsearch");
+			   $$ = newp->value;
+			}
+		    }
+		|
+		    {
+		      $$ = 0;
+		    }
+		;
+
 %%
 
 static void
@@ -560,8 +602,8 @@ yyerror (const char *s)
 static int
 bitfield_compare (const void *p1, const void *p2)
 {
-  struct known_bitfield *f1 = (struct known_bitfield *) p1;
-  struct known_bitfield *f2 = (struct known_bitfield *) p2;
+  const struct known_bitfield *f1 = (const struct known_bitfield *) p1;
+  const struct known_bitfield *f2 = (const struct known_bitfield *) p2;
 
   return strcmp (f1->name, f2->name);
 }
@@ -1109,6 +1151,25 @@ print_op_fct (const void *nodep, VISIT value,
 }
 
 
+static int
+type_compare (const void *p1, const void *p2)
+{
+  const struct instruction_type *f1 = (const struct instruction_type *) p1;
+  const struct instruction_type *f2 = (const struct instruction_type *) p2;
+
+  return strcmp (f1->name, f2->name);
+}
+
+static void
+print_type (const void *p, const VISIT which,
+	    const int depth __attribute__ ((unused)))
+{
+  const struct instruction_type *i = *(const struct instruction_type **) p;
+  if (which == postorder || which == leaf)
+    fprintf (outfile, "  TYPE_%s = %lu,\n", i->name, i->value);
+}
+
+
 #if NMNES < 2
 # error "bogus NMNES value"
 #endif
@@ -1145,6 +1206,8 @@ instrtable_out (void)
 	  fprintf (outfile, "#define OFF%d_3_BIAS %d\n", i + 1, minoff[i][2]);
 	}
     }
+  fprintf (outfile, "#define TYPE_BITS %ld\n",
+	   lrint (ceil (log2 (typecnt))));
 
   fputs ("\n#include <i386_data.h>\n\n", outfile);
 
@@ -1190,6 +1253,11 @@ instrtable_out (void)
     }
 
 
+  fputs ("enum instruction_types {\n", outfile);
+  twalk (types, print_type);
+  fputs ("};\n", outfile);
+
+
   fputs ("static const struct instr_enc instrtab[] =\n{\n", outfile);
   struct instruction *instr;
   for (instr = instructions; instr != NULL; instr = instr->next)
@@ -1241,6 +1309,8 @@ instrtable_out (void)
 		     MAX (0, instr->operands[i].off3 - minoff[i][2]));
 	}
 
+      fprintf (outfile, " .type = %lu,", instr->type);
+
       fputs (" },\n", outfile);
     }
   fputs ("};\n", outfile);
diff --git a/src/objdump.c b/src/objdump.c
index 87290cc..90cbc10 100644
--- a/src/objdump.c
+++ b/src/objdump.c
@@ -646,7 +646,8 @@ struct disasm_info
 // XXX This is not the preferred output for all architectures.  Needs
 // XXX customization, too.
 static int
-disasm_output (char *buf, size_t buflen, void *arg)
+disasm_output (char *buf, size_t buflen, void *arg,
+	       uint64_t flags __attribute__ ((unused)))
 {
   struct disasm_info *info = (struct disasm_info *) arg;
 

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