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