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