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