xref: /third_party/elfutils/libcpu/i386_disasm.c (revision da0c48c4)
1/* Disassembler for x86.
2   Copyright (C) 2007, 2008, 2009, 2011 Red Hat, Inc.
3   This file is part of elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 2007.
5
6   This file is free software; you can redistribute it and/or modify
7   it under the terms of either
8
9     * the GNU Lesser General Public License as published by the Free
10       Software Foundation; either version 3 of the License, or (at
11       your option) any later version
12
13   or
14
15     * the GNU General Public License as published by the Free
16       Software Foundation; either version 2 of the License, or (at
17       your option) any later version
18
19   or both in parallel, as here.
20
21   elfutils is distributed in the hope that it will be useful, but
22   WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   General Public License for more details.
25
26   You should have received copies of the GNU General Public License and
27   the GNU Lesser General Public License along with this program.  If
28   not, see <http://www.gnu.org/licenses/>.  */
29
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <assert.h>
35#include <config.h>
36#include <ctype.h>
37#include <errno.h>
38#include <gelf.h>
39#include <stddef.h>
40#include <stdint.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include "../libebl/libeblP.h"
45
46#define MACHINE_ENCODING LITTLE_ENDIAN
47#include "memory-access.h"
48
49
50#ifndef MNEFILE
51# define MNEFILE "i386.mnemonics"
52#endif
53
54#define MNESTRFIELD(line) MNESTRFIELD1 (line)
55#define MNESTRFIELD1(line) str##line
56static const union mnestr_t
57{
58  struct
59  {
60#define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)];
61#include MNEFILE
62#undef MNE
63  };
64  char str[0];
65} mnestr =
66  {
67    {
68#define MNE(name) #name,
69#include MNEFILE
70#undef MNE
71    }
72  };
73
74/* The index can be stored in the instrtab.  */
75enum
76  {
77#define MNE(name) MNE_##name,
78#include MNEFILE
79#undef MNE
80    MNE_INVALID
81  };
82
83static const unsigned short int mneidx[] =
84  {
85#define MNE(name) \
86  [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)),
87#include MNEFILE
88#undef MNE
89  };
90
91
92enum
93  {
94    idx_rex_b = 0,
95    idx_rex_x,
96    idx_rex_r,
97    idx_rex_w,
98    idx_rex,
99    idx_cs,
100    idx_ds,
101    idx_es,
102    idx_fs,
103    idx_gs,
104    idx_ss,
105    idx_data16,
106    idx_addr16,
107    idx_rep,
108    idx_repne,
109    idx_lock
110  };
111
112enum
113  {
114#define prefbit(pref) has_##pref = 1 << idx_##pref
115    prefbit (rex_b),
116    prefbit (rex_x),
117    prefbit (rex_r),
118    prefbit (rex_w),
119    prefbit (rex),
120    prefbit (cs),
121    prefbit (ds),
122    prefbit (es),
123    prefbit (fs),
124    prefbit (gs),
125    prefbit (ss),
126    prefbit (data16),
127    prefbit (addr16),
128    prefbit (rep),
129    prefbit (repne),
130    prefbit (lock)
131#undef prefbit
132  };
133#define SEGMENT_PREFIXES \
134  (has_cs | has_ds | has_es | has_fs | has_gs | has_ss)
135
136#define prefix_cs	0x2e
137#define prefix_ds	0x3e
138#define prefix_es	0x26
139#define prefix_fs	0x64
140#define prefix_gs	0x65
141#define prefix_ss	0x36
142#define prefix_data16	0x66
143#define prefix_addr16	0x67
144#define prefix_rep	0xf3
145#define prefix_repne	0xf2
146#define prefix_lock	0xf0
147
148
149static const uint8_t known_prefixes[] =
150  {
151#define newpref(pref) [idx_##pref] = prefix_##pref
152    newpref (cs),
153    newpref (ds),
154    newpref (es),
155    newpref (fs),
156    newpref (gs),
157    newpref (ss),
158    newpref (data16),
159    newpref (addr16),
160    newpref (rep),
161    newpref (repne),
162    newpref (lock)
163#undef newpref
164  };
165#define nknown_prefixes (sizeof (known_prefixes) / sizeof (known_prefixes[0]))
166
167
168#if 0
169static const char *prefix_str[] =
170  {
171#define newpref(pref) [idx_##pref] = #pref
172    newpref (cs),
173    newpref (ds),
174    newpref (es),
175    newpref (fs),
176    newpref (gs),
177    newpref (ss),
178    newpref (data16),
179    newpref (addr16),
180    newpref (rep),
181    newpref (repne),
182    newpref (lock)
183#undef newpref
184  };
185#endif
186
187
188static const char amd3dnowstr[] =
189#define MNE_3DNOW_PAVGUSB 1
190  "pavgusb\0"
191#define MNE_3DNOW_PFADD (MNE_3DNOW_PAVGUSB + 8)
192  "pfadd\0"
193#define MNE_3DNOW_PFSUB (MNE_3DNOW_PFADD + 6)
194  "pfsub\0"
195#define MNE_3DNOW_PFSUBR (MNE_3DNOW_PFSUB + 6)
196  "pfsubr\0"
197#define MNE_3DNOW_PFACC (MNE_3DNOW_PFSUBR + 7)
198  "pfacc\0"
199#define MNE_3DNOW_PFCMPGE (MNE_3DNOW_PFACC + 6)
200  "pfcmpge\0"
201#define MNE_3DNOW_PFCMPGT (MNE_3DNOW_PFCMPGE + 8)
202  "pfcmpgt\0"
203#define MNE_3DNOW_PFCMPEQ (MNE_3DNOW_PFCMPGT + 8)
204  "pfcmpeq\0"
205#define MNE_3DNOW_PFMIN (MNE_3DNOW_PFCMPEQ + 8)
206  "pfmin\0"
207#define MNE_3DNOW_PFMAX (MNE_3DNOW_PFMIN + 6)
208  "pfmax\0"
209#define MNE_3DNOW_PI2FD (MNE_3DNOW_PFMAX + 6)
210  "pi2fd\0"
211#define MNE_3DNOW_PF2ID (MNE_3DNOW_PI2FD + 6)
212  "pf2id\0"
213#define MNE_3DNOW_PFRCP (MNE_3DNOW_PF2ID + 6)
214  "pfrcp\0"
215#define MNE_3DNOW_PFRSQRT (MNE_3DNOW_PFRCP + 6)
216  "pfrsqrt\0"
217#define MNE_3DNOW_PFMUL (MNE_3DNOW_PFRSQRT + 8)
218  "pfmul\0"
219#define MNE_3DNOW_PFRCPIT1 (MNE_3DNOW_PFMUL + 6)
220  "pfrcpit1\0"
221#define MNE_3DNOW_PFRSQIT1 (MNE_3DNOW_PFRCPIT1 + 9)
222  "pfrsqit1\0"
223#define MNE_3DNOW_PFRCPIT2 (MNE_3DNOW_PFRSQIT1 + 9)
224  "pfrcpit2\0"
225#define MNE_3DNOW_PMULHRW (MNE_3DNOW_PFRCPIT2 + 9)
226  "pmulhrw";
227
228#define AMD3DNOW_LOW_IDX 0x0d
229#define AMD3DNOW_HIGH_IDX (sizeof (amd3dnow) + AMD3DNOW_LOW_IDX - 1)
230#define AMD3DNOW_IDX(val) ((val) - AMD3DNOW_LOW_IDX)
231static const unsigned char amd3dnow[] =
232  {
233    [AMD3DNOW_IDX (0xbf)] = MNE_3DNOW_PAVGUSB,
234    [AMD3DNOW_IDX (0x9e)] = MNE_3DNOW_PFADD,
235    [AMD3DNOW_IDX (0x9a)] = MNE_3DNOW_PFSUB,
236    [AMD3DNOW_IDX (0xaa)] = MNE_3DNOW_PFSUBR,
237    [AMD3DNOW_IDX (0xae)] = MNE_3DNOW_PFACC,
238    [AMD3DNOW_IDX (0x90)] = MNE_3DNOW_PFCMPGE,
239    [AMD3DNOW_IDX (0xa0)] = MNE_3DNOW_PFCMPGT,
240    [AMD3DNOW_IDX (0xb0)] = MNE_3DNOW_PFCMPEQ,
241    [AMD3DNOW_IDX (0x94)] = MNE_3DNOW_PFMIN,
242    [AMD3DNOW_IDX (0xa4)] = MNE_3DNOW_PFMAX,
243    [AMD3DNOW_IDX (0x0d)] = MNE_3DNOW_PI2FD,
244    [AMD3DNOW_IDX (0x1d)] = MNE_3DNOW_PF2ID,
245    [AMD3DNOW_IDX (0x96)] = MNE_3DNOW_PFRCP,
246    [AMD3DNOW_IDX (0x97)] = MNE_3DNOW_PFRSQRT,
247    [AMD3DNOW_IDX (0xb4)] = MNE_3DNOW_PFMUL,
248    [AMD3DNOW_IDX (0xa6)] = MNE_3DNOW_PFRCPIT1,
249    [AMD3DNOW_IDX (0xa7)] = MNE_3DNOW_PFRSQIT1,
250    [AMD3DNOW_IDX (0xb6)] = MNE_3DNOW_PFRCPIT2,
251    [AMD3DNOW_IDX (0xb7)] = MNE_3DNOW_PMULHRW
252  };
253
254
255struct output_data
256{
257  GElf_Addr addr;
258  int *prefixes;
259  size_t opoff1;
260  size_t opoff2;
261  size_t opoff3;
262  char *bufp;
263  size_t *bufcntp;
264  size_t bufsize;
265  const uint8_t *data;
266  const uint8_t **param_start;
267  const uint8_t *end;
268  char *labelbuf;
269  size_t labelbufsize;
270  enum
271    {
272      addr_none = 0,
273      addr_abs_symbolic,
274      addr_abs_always,
275      addr_rel_symbolic,
276      addr_rel_always
277    } symaddr_use;
278  GElf_Addr symaddr;
279};
280
281
282#ifndef DISFILE
283# define DISFILE "i386_dis.h"
284#endif
285#include DISFILE
286
287
288#define ADD_CHAR(ch) \
289  do {									      \
290    if (unlikely (bufcnt == bufsize))					      \
291      goto enomem;							      \
292    buf[bufcnt++] = (ch);						      \
293  } while (0)
294
295#define ADD_STRING(str) \
296  do {									      \
297    const char *_str0 = (str);						      \
298    size_t _len0 = strlen (_str0);					      \
299    ADD_NSTRING (_str0, _len0);						      \
300  } while (0)
301
302#define ADD_NSTRING(str, len) \
303  do {									      \
304    const char *_str = (str);						      \
305    size_t _len = (len);						      \
306    if (unlikely (bufcnt + _len > bufsize))				      \
307      goto enomem;							      \
308    memcpy (buf + bufcnt, _str, _len);					      \
309    bufcnt += _len;							      \
310  } while (0)
311
312
313int
314i386_disasm (Ebl *ebl __attribute__((unused)),
315	     const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
316	     const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
317	     void *outcbarg, void *symcbarg)
318{
319  const char *save_fmt = fmt;
320
321#define BUFSIZE 512
322  char initbuf[BUFSIZE];
323  int prefixes;
324  size_t bufcnt;
325  size_t bufsize = BUFSIZE;
326  char *buf = initbuf;
327  const uint8_t *param_start;
328
329  struct output_data output_data =
330    {
331      .prefixes = &prefixes,
332      .bufp = buf,
333      .bufsize = bufsize,
334      .bufcntp = &bufcnt,
335      .param_start = &param_start,
336      .end = end
337    };
338
339  int retval = 0;
340  while (1)
341    {
342      prefixes = 0;
343
344      const uint8_t *data = *startp;
345      const uint8_t *begin = data;
346
347      /* Recognize all prefixes.  */
348      int last_prefix_bit = 0;
349      while (data < end)
350	{
351	  unsigned int i;
352	  for (i = idx_cs; i < nknown_prefixes; ++i)
353	    if (known_prefixes[i] == *data)
354	      break;
355	  if (i == nknown_prefixes)
356	    break;
357
358	  prefixes |= last_prefix_bit = 1 << i;
359
360	  ++data;
361	}
362
363#ifdef X86_64
364      if (data < end && (*data & 0xf0) == 0x40)
365	prefixes |= ((*data++) & 0xf) | has_rex;
366#endif
367
368      bufcnt = 0;
369      size_t cnt = 0;
370
371      const uint8_t *curr = match_data;
372      const uint8_t *const match_end = match_data + sizeof (match_data);
373
374      assert (data <= end);
375      if (data == end)
376	{
377	  if (prefixes != 0)
378	    goto print_prefix;
379
380	  retval = -1;
381	  goto do_ret;
382	}
383
384    next_match:
385      while (curr < match_end)
386	{
387	  uint_fast8_t len = *curr++;
388	  uint_fast8_t clen = len >> 4;
389	  len &= 0xf;
390	  const uint8_t *next_curr = curr + clen + (len - clen) * 2;
391
392	  assert (len > 0);
393	  assert (curr + clen + 2 * (len - clen) <= match_end);
394
395	  const uint8_t *codep = data;
396	  int correct_prefix = 0;
397	  int opoff = 0;
398
399	  if (data > begin && codep[-1] == *curr && clen > 0)
400	    {
401	      /* We match a prefix byte.  This is exactly one byte and
402		 is matched exactly, without a mask.  */
403	      --len;
404	      --clen;
405	      opoff = 8;
406
407	      ++curr;
408
409	      if (last_prefix_bit == 0)
410		goto invalid_op;
411	      correct_prefix = last_prefix_bit;
412	    }
413
414	  size_t avail = len;
415	  while (clen > 0)
416	    {
417	      if (*codep++ != *curr++)
418		goto not;
419	      --avail;
420	      --clen;
421	      if (codep == end && avail > 0)
422		goto do_ret;
423	    }
424
425	  while (avail > 0)
426	    {
427	      uint_fast8_t masked = *codep++ & *curr++;
428	      if (masked != *curr++)
429		{
430		not:
431		  curr = next_curr;
432		  ++cnt;
433		  bufcnt = 0;
434		  goto next_match;
435		}
436
437	      --avail;
438	      if (codep == end && avail > 0)
439		goto do_ret;
440	    }
441
442	  if (len > end - data)
443	    /* There is not enough data for the entire instruction.  The
444	       caller can figure this out by looking at the pointer into
445	       the input data.  */
446	    goto do_ret;
447
448	  if (correct_prefix != 0 && (prefixes & correct_prefix) == 0)
449	    goto invalid_op;
450	  prefixes ^= correct_prefix;
451
452	  if (0)
453	    {
454	      /* Resize the buffer.  */
455	      char *oldbuf;
456	    enomem:
457	      oldbuf = buf;
458	      if (buf == initbuf)
459		buf = malloc (2 * bufsize);
460	      else
461		buf = realloc (buf, 2 * bufsize);
462	      if (buf == NULL)
463		{
464		  buf = oldbuf;
465		  retval = ENOMEM;
466		  goto do_ret;
467		}
468	      bufsize *= 2;
469
470	      output_data.bufp = buf;
471	      output_data.bufsize = bufsize;
472	      bufcnt = 0;
473
474	      if (data == end)
475		{
476		  if (prefixes == 0)
477		    goto invalid_op;
478		  goto print_prefix;
479		}
480
481	      /* gcc is not clever enough to see the following variables
482		 are not used uninitialized.  */
483	      asm (""
484		   : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
485		     "=mr" (next_curr), "=mr" (len));
486	    }
487
488	  size_t prefix_size = 0;
489
490	  // XXXonly print as prefix if valid?
491	  if ((prefixes & has_lock) != 0)
492	    {
493	      ADD_STRING ("lock ");
494	      prefix_size += 5;
495	    }
496
497	  if (instrtab[cnt].rep)
498	    {
499	      if ((prefixes & has_rep) !=  0)
500		{
501		  ADD_STRING ("rep ");
502		  prefix_size += 4;
503		}
504	    }
505	  else if (instrtab[cnt].repe
506		   && (prefixes & (has_rep | has_repne)) != 0)
507	    {
508	      if ((prefixes & has_repne) != 0)
509		{
510		  ADD_STRING ("repne ");
511		  prefix_size += 6;
512		}
513	      else if ((prefixes & has_rep) != 0)
514		{
515		  ADD_STRING ("repe ");
516		  prefix_size += 5;
517		}
518	    }
519	  else if ((prefixes & (has_rep | has_repne)) != 0)
520	    {
521	      uint_fast8_t byte;
522	    print_prefix:
523	      bufcnt = 0;
524	      byte = *begin;
525	      /* This is a prefix byte.  Print it.  */
526	      switch (byte)
527		{
528		case prefix_rep:
529		  ADD_STRING ("rep");
530		  break;
531		case prefix_repne:
532		  ADD_STRING ("repne");
533		  break;
534		case prefix_cs:
535		  ADD_STRING ("cs");
536		  break;
537		case prefix_ds:
538		  ADD_STRING ("ds");
539		  break;
540		case prefix_es:
541		  ADD_STRING ("es");
542		  break;
543		case prefix_fs:
544		  ADD_STRING ("fs");
545		  break;
546		case prefix_gs:
547		  ADD_STRING ("gs");
548		  break;
549		case prefix_ss:
550		  ADD_STRING ("ss");
551		  break;
552		case prefix_data16:
553		  ADD_STRING ("data16");
554		  break;
555		case prefix_addr16:
556		  ADD_STRING ("addr16");
557		  break;
558		case prefix_lock:
559		  ADD_STRING ("lock");
560		  break;
561#ifdef X86_64
562		case 0x40 ... 0x4f:
563		  ADD_STRING ("rex");
564		  if (byte != 0x40)
565		    {
566		      ADD_CHAR ('.');
567		      if (byte & 0x8)
568			ADD_CHAR ('w');
569		      if (byte & 0x4)
570			ADD_CHAR ('r');
571		      if (byte & 0x3)
572			ADD_CHAR ('x');
573		      if (byte & 0x1)
574			ADD_CHAR ('b');
575		    }
576		  break;
577#endif
578		default:
579		  /* Cannot happen.  */
580		  puts ("unknown prefix");
581		  abort ();
582		}
583	      data = begin + 1;
584	      ++addr;
585
586	      goto out;
587	    }
588
589	  /* We have a match.  First determine how many bytes are
590	     needed for the addressing mode.  */
591	  param_start = codep;
592	  if (instrtab[cnt].modrm)
593	    {
594	      uint_fast8_t modrm = codep[-1];
595
596#ifndef X86_64
597	      if (likely ((prefixes & has_addr16) != 0))
598		{
599		  /* Account for displacement.  */
600		  if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
601		    param_start += 2;
602		  else if ((modrm & 0xc0) == 0x40)
603		    param_start += 1;
604		}
605	      else
606#endif
607		{
608		  /* Account for SIB.  */
609		  if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
610		    param_start += 1;
611
612		  /* Account for displacement.  */
613		  if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
614		      || ((modrm & 0xc7) == 0x4
615			  && param_start < end
616			  && (codep[0] & 0x7) == 0x5))
617		    param_start += 4;
618		  else if ((modrm & 0xc0) == 0x40)
619		    param_start += 1;
620		}
621
622	      if (unlikely (param_start > end))
623		goto not;
624	    }
625
626	  output_data.addr = addr + (data - begin);
627	  output_data.data = data;
628
629	  unsigned long string_end_idx = 0;
630	  fmt = save_fmt;
631	  const char *deferred_start = NULL;
632	  size_t deferred_len = 0;
633	  // XXX Can we get this from color.c?
634	  static const char color_off[] = "\e[0m";
635	  while (*fmt != '\0')
636	    {
637	      if (*fmt != '%')
638		{
639		  char ch = *fmt++;
640		  if (ch == '\\')
641		    {
642		      switch ((ch = *fmt++))
643			{
644			case '0' ... '7':
645			  {
646			    int val = ch - '0';
647			    ch = *fmt;
648			    if (ch >= '0' && ch <= '7')
649			      {
650				val *= 8;
651				val += ch - '0';
652				ch = *++fmt;
653				if (ch >= '0' && ch <= '7' && val < 32)
654				  {
655				    val *= 8;
656				    val += ch - '0';
657				    ++fmt;
658				  }
659			      }
660			    ch = val;
661			  }
662			  break;
663
664			case 'n':
665			  ch = '\n';
666			  break;
667
668			case 't':
669			  ch = '\t';
670			  break;
671
672			default:
673			  retval = EINVAL;
674			  goto do_ret;
675			}
676		    }
677		  else if (ch == '\e' && *fmt == '[')
678		    {
679		      deferred_start = fmt - 1;
680		      do
681			++fmt;
682		      while (*fmt != 'm' && *fmt != '\0');
683
684		      if (*fmt == 'm')
685			{
686			  deferred_len = ++fmt - deferred_start;
687			  continue;
688			}
689
690		      fmt = deferred_start + 1;
691		      deferred_start = NULL;
692		    }
693		  ADD_CHAR (ch);
694		  continue;
695		}
696	      ++fmt;
697
698	      int width = 0;
699	      while (isdigit (*fmt))
700		width = width * 10 + (*fmt++ - '0');
701
702	      int prec = 0;
703	      if (*fmt == '.')
704		while (isdigit (*++fmt))
705		  prec = prec * 10 + (*fmt - '0');
706
707	      size_t start_idx = bufcnt;
708	      size_t non_printing = 0;
709	      switch (*fmt++)
710		{
711		  char mnebuf[16];
712		  const char *str;
713
714		case 'm':
715		  /* Mnemonic.  */
716
717		  if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
718		    {
719		      switch (*data)
720			{
721#ifdef X86_64
722			case 0x90:
723			  if (prefixes & has_rex_b)
724			    goto not;
725			  str = "nop";
726			  break;
727#endif
728
729			case 0x98:
730#ifdef X86_64
731			  if (prefixes == (has_rex_w | has_rex))
732			    {
733			      str = "cltq";
734			      break;
735			    }
736#endif
737			  if (prefixes & ~has_data16)
738			    goto print_prefix;
739			  str = prefixes & has_data16 ? "cbtw" : "cwtl";
740			  break;
741
742			case 0x99:
743#ifdef X86_64
744			  if (prefixes == (has_rex_w | has_rex))
745			    {
746			      str = "cqto";
747			      break;
748			    }
749#endif
750			  if (prefixes & ~has_data16)
751			    goto print_prefix;
752			  str = prefixes & has_data16 ? "cwtd" : "cltd";
753			  break;
754
755			case 0xe3:
756			  if (prefixes & ~has_addr16)
757			    goto print_prefix;
758#ifdef X86_64
759			  str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
760#else
761			  str = prefixes & has_addr16 ? "jcxz" : "jecxz";
762#endif
763			  break;
764
765			case 0x0f:
766			  if (data[1] == 0x0f)
767			    {
768			      /* AMD 3DNOW.  We need one more byte.  */
769			      if (param_start >= end)
770				goto not;
771			      if (*param_start < AMD3DNOW_LOW_IDX
772				  || *param_start > AMD3DNOW_HIGH_IDX)
773				goto not;
774			      unsigned int idx
775				= amd3dnow[AMD3DNOW_IDX (*param_start)];
776			      if (idx == 0)
777				goto not;
778			      str = amd3dnowstr + idx - 1;
779			      /* Eat the immediate byte indicating the
780				 operation.  */
781			      ++param_start;
782			      break;
783			    }
784#ifdef X86_64
785			  if (data[1] == 0xc7)
786			    {
787			      str = ((prefixes & has_rex_w)
788				     ? "cmpxchg16b" : "cmpxchg8b");
789			      break;
790			    }
791#endif
792			  if (data[1] == 0xc2)
793			    {
794			      if (param_start >= end)
795				goto not;
796			      if (*param_start > 7)
797				goto not;
798			      static const char cmpops[][9] =
799				{
800				  [0] = "cmpeq",
801				  [1] = "cmplt",
802				  [2] = "cmple",
803				  [3] = "cmpunord",
804				  [4] = "cmpneq",
805				  [5] = "cmpnlt",
806				  [6] = "cmpnle",
807				  [7] = "cmpord"
808				};
809			      char *cp = stpcpy (mnebuf, cmpops[*param_start]);
810			      if (correct_prefix & (has_rep | has_repne))
811				*cp++ = 's';
812			      else
813				*cp++ = 'p';
814			      if (correct_prefix & (has_data16 | has_repne))
815				*cp++ = 'd';
816			      else
817				*cp++ = 's';
818			      *cp = '\0';
819			      str = mnebuf;
820			      /* Eat the immediate byte indicating the
821				 operation.  */
822			      ++param_start;
823			      break;
824			    }
825			  FALLTHROUGH;
826			default:
827			  str = "INVALID not handled";
828			  break;
829			}
830		    }
831		  else
832		    str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
833
834		  if (deferred_start != NULL)
835		    {
836		      ADD_NSTRING (deferred_start, deferred_len);
837		      non_printing += deferred_len;
838		    }
839
840		  ADD_STRING (str);
841
842		  switch (instrtab[cnt].suffix)
843		    {
844		    case suffix_none:
845		      break;
846
847		    case suffix_w:
848		      if ((codep[-1] & 0xc0) != 0xc0)
849			{
850			  char ch;
851
852			  if (data[0] & 1)
853			    {
854			      if (prefixes & has_data16)
855				ch = 'w';
856#ifdef X86_64
857			      else if (prefixes & has_rex_w)
858				ch = 'q';
859#endif
860			      else
861				ch = 'l';
862			    }
863			  else
864			    ch = 'b';
865
866			  ADD_CHAR (ch);
867			}
868		      break;
869
870		    case suffix_w0:
871		      if ((codep[-1] & 0xc0) != 0xc0)
872			ADD_CHAR ('l');
873		      break;
874
875		    case suffix_w1:
876		      if ((data[0] & 0x4) == 0)
877			ADD_CHAR ('l');
878		      break;
879
880		    case suffix_W:
881		      if (prefixes & has_data16)
882			{
883			  ADD_CHAR ('w');
884			  prefixes &= ~has_data16;
885			}
886#ifdef X86_64
887		      else
888			ADD_CHAR ('q');
889#endif
890		      break;
891
892		    case suffix_W1:
893		      if (prefixes & has_data16)
894			{
895			  ADD_CHAR ('w');
896			  prefixes &= ~has_data16;
897			}
898#ifdef X86_64
899		      else if (prefixes & has_rex_w)
900			ADD_CHAR ('q');
901#endif
902		      break;
903
904		    case suffix_tttn:;
905		      static const char tttn[16][3] =
906			{
907			  "o", "no", "b", "ae", "e", "ne", "be", "a",
908			  "s", "ns", "p", "np", "l", "ge", "le", "g"
909			};
910		      ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
911		      break;
912
913		    case suffix_D:
914		      if ((codep[-1] & 0xc0) != 0xc0)
915			ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
916		      break;
917
918		    default:
919		      printf("unknown suffix %d\n", instrtab[cnt].suffix);
920		      abort ();
921		    }
922
923		  if (deferred_start != NULL)
924		    {
925		      ADD_STRING (color_off);
926		      non_printing += strlen (color_off);
927		    }
928
929		  string_end_idx = bufcnt;
930		  break;
931
932		case 'o':
933		  if (prec == 1 && instrtab[cnt].fct1 != 0)
934		    {
935		      /* First parameter.  */
936		      if (deferred_start != NULL)
937			{
938			  ADD_NSTRING (deferred_start, deferred_len);
939			  non_printing += deferred_len;
940			}
941
942		      if (instrtab[cnt].str1 != 0)
943			ADD_STRING (op1_str
944				    + op1_str_idx[instrtab[cnt].str1 - 1]);
945
946		      output_data.opoff1 = (instrtab[cnt].off1_1
947					    + OFF1_1_BIAS - opoff);
948		      output_data.opoff2 = (instrtab[cnt].off1_2
949					    + OFF1_2_BIAS - opoff);
950		      output_data.opoff3 = (instrtab[cnt].off1_3
951					    + OFF1_3_BIAS - opoff);
952		      int r = op1_fct[instrtab[cnt].fct1] (&output_data);
953		      if (r < 0)
954			goto not;
955		      if (r > 0)
956			goto enomem;
957
958		      if (deferred_start != NULL)
959			{
960			  ADD_STRING (color_off);
961			  non_printing += strlen (color_off);
962			}
963
964		      string_end_idx = bufcnt;
965		    }
966		  else if (prec == 2 && instrtab[cnt].fct2 != 0)
967		    {
968		      /* Second parameter.  */
969		      if (deferred_start != NULL)
970			{
971			  ADD_NSTRING (deferred_start, deferred_len);
972			  non_printing += deferred_len;
973			}
974
975		      if (instrtab[cnt].str2 != 0)
976			ADD_STRING (op2_str
977				    + op2_str_idx[instrtab[cnt].str2 - 1]);
978
979		      output_data.opoff1 = (instrtab[cnt].off2_1
980					    + OFF2_1_BIAS - opoff);
981		      output_data.opoff2 = (instrtab[cnt].off2_2
982					    + OFF2_2_BIAS - opoff);
983		      output_data.opoff3 = (instrtab[cnt].off2_3
984					    + OFF2_3_BIAS - opoff);
985		      int r = op2_fct[instrtab[cnt].fct2] (&output_data);
986		      if (r < 0)
987			goto not;
988		      if (r > 0)
989			goto enomem;
990
991		      if (deferred_start != NULL)
992			{
993			  ADD_STRING (color_off);
994			  non_printing += strlen (color_off);
995			}
996
997		      string_end_idx = bufcnt;
998		    }
999		  else if (prec == 3 && instrtab[cnt].fct3 != 0)
1000		    {
1001		      /* Third parameter.  */
1002		      if (deferred_start != NULL)
1003			{
1004			  ADD_NSTRING (deferred_start, deferred_len);
1005			  non_printing += deferred_len;
1006			}
1007
1008		      if (instrtab[cnt].str3 != 0)
1009			ADD_STRING (op3_str
1010				    + op3_str_idx[instrtab[cnt].str3 - 1]);
1011
1012		      output_data.opoff1 = (instrtab[cnt].off3_1
1013					    + OFF3_1_BIAS - opoff);
1014		      output_data.opoff2 = (instrtab[cnt].off3_2
1015					    + OFF3_2_BIAS - opoff);
1016#ifdef OFF3_3_BITS
1017		      output_data.opoff3 = (instrtab[cnt].off3_3
1018					    + OFF3_3_BIAS - opoff);
1019#else
1020		      output_data.opoff3 = 0;
1021#endif
1022		      int r = op3_fct[instrtab[cnt].fct3] (&output_data);
1023		      if (r < 0)
1024			goto not;
1025		      if (r > 0)
1026			goto enomem;
1027
1028		      if (deferred_start != NULL)
1029			{
1030			  ADD_STRING (color_off);
1031			  non_printing += strlen (color_off);
1032			}
1033
1034		      string_end_idx = bufcnt;
1035		    }
1036		  else
1037		    start_idx = bufcnt = string_end_idx;
1038		  break;
1039
1040		case 'e':
1041		  string_end_idx = bufcnt;
1042		  break;
1043
1044		case 'a':
1045		  /* Pad to requested column.  */
1046		  while (bufcnt - non_printing < (size_t) width)
1047		    ADD_CHAR (' ');
1048		  width = 0;
1049		  break;
1050
1051		case 'l':
1052		  if (deferred_start != NULL)
1053		    {
1054		      ADD_NSTRING (deferred_start, deferred_len);
1055		      non_printing += deferred_len;
1056		    }
1057
1058		  if (output_data.labelbuf != NULL
1059		      && output_data.labelbuf[0] != '\0')
1060		    {
1061		      ADD_STRING (output_data.labelbuf);
1062		      output_data.labelbuf[0] = '\0';
1063		      string_end_idx = bufcnt;
1064		    }
1065		  else if (output_data.symaddr_use != addr_none)
1066		    {
1067		      GElf_Addr symaddr = output_data.symaddr;
1068		      if (output_data.symaddr_use >= addr_rel_symbolic)
1069			symaddr += addr + param_start - begin;
1070
1071		      // XXX Lookup symbol based on symaddr
1072		      const char *symstr = NULL;
1073		      if (symcb != NULL
1074			  && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
1075				    &output_data.labelbuf,
1076				    &output_data.labelbufsize, symcbarg) == 0)
1077			symstr = output_data.labelbuf;
1078
1079		      size_t bufavail = bufsize - bufcnt;
1080		      int r = 0;
1081		      if (symstr != NULL)
1082			r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
1083				      symstr);
1084		      else if (output_data.symaddr_use == addr_abs_always
1085			       || output_data.symaddr_use == addr_rel_always)
1086			r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
1087				      (uint64_t) symaddr);
1088
1089		      assert (r >= 0);
1090		      if ((size_t) r >= bufavail)
1091			goto enomem;
1092		      bufcnt += r;
1093		      string_end_idx = bufcnt;
1094
1095		      output_data.symaddr_use = addr_none;
1096		    }
1097		  if (deferred_start != NULL)
1098		    {
1099		      ADD_STRING (color_off);
1100		      non_printing += strlen (color_off);
1101		    }
1102		  break;
1103
1104		default:
1105		  abort ();
1106		}
1107
1108	      deferred_start = NULL;
1109
1110	      /* Pad according to the specified width.  */
1111	      while (bufcnt + prefix_size - non_printing < start_idx + width)
1112		ADD_CHAR (' ');
1113	      prefix_size = 0;
1114	    }
1115
1116	  if ((prefixes & SEGMENT_PREFIXES) != 0)
1117	    goto print_prefix;
1118
1119	  assert (string_end_idx != ~0ul);
1120	  bufcnt = string_end_idx;
1121
1122	  addr += param_start - begin;
1123	  data = param_start;
1124
1125	  goto out;
1126	}
1127
1128      /* Invalid (or at least unhandled) opcode.  */
1129    invalid_op:
1130      if (prefixes != 0)
1131	goto print_prefix;
1132      /* Make sure we get past the unrecognized opcode if we haven't yet.  */
1133      if (*startp == data)
1134	++data;
1135      ADD_STRING ("(bad)");
1136      addr += data - begin;
1137
1138    out:
1139      if (bufcnt == bufsize)
1140	goto enomem;
1141      buf[bufcnt] = '\0';
1142
1143      *startp = data;
1144      retval = outcb (buf, bufcnt, outcbarg);
1145      if (retval != 0)
1146	goto do_ret;
1147    }
1148
1149 do_ret:
1150  free (output_data.labelbuf);
1151  if (buf != initbuf)
1152    free (buf);
1153
1154  return retval;
1155}
1156