• 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 <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
56 static 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.  */
75 enum
76   {
77 #define MNE(name) MNE_##name,
78 #include MNEFILE
79 #undef MNE
80     MNE_INVALID
81   };
82 
83 static 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 
92 enum
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 
112 enum
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 
149 static 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
169 static 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 
188 static 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)
231 static 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 
255 struct 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 
313 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)314 i386_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