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 Red Hat elfutils.
      4    Written by Ulrich Drepper <drepper (at) 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 *_str0 = (str);						      \
    297     size_t _len0 = strlen (_str0);					      \
    298     ADD_NSTRING (_str0, _len0);						      \
    299   } while (0)
    300 
    301 #define ADD_NSTRING(str, len) \
    302   do {									      \
    303     const char *_str = (str);						      \
    304     size_t _len = (len);						      \
    305     if (unlikely (bufcnt + _len > bufsize))				      \
    306       goto enomem;							      \
    307     memcpy (buf + bufcnt, _str, _len);					      \
    308     bufcnt += _len;							      \
    309   } while (0)
    310 
    311 
    312 int
    313 i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
    314 	     const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
    315 	     void *outcbarg, void *symcbarg)
    316 {
    317   const char *save_fmt = fmt;
    318 
    319 #define BUFSIZE 512
    320   char initbuf[BUFSIZE];
    321   int prefixes;
    322   size_t bufcnt;
    323   size_t bufsize = BUFSIZE;
    324   char *buf = initbuf;
    325   const uint8_t *param_start;
    326 
    327   struct output_data output_data =
    328     {
    329       .prefixes = &prefixes,
    330       .bufp = buf,
    331       .bufsize = bufsize,
    332       .bufcntp = &bufcnt,
    333       .param_start = &param_start,
    334       .end = end
    335     };
    336 
    337   int retval = 0;
    338   while (1)
    339     {
    340       prefixes = 0;
    341 
    342       const uint8_t *data = *startp;
    343       const uint8_t *begin = data;
    344 
    345       /* Recognize all prefixes.  */
    346       int last_prefix_bit = 0;
    347       while (data < end)
    348 	{
    349 	  unsigned int i;
    350 	  for (i = idx_cs; i < nknown_prefixes; ++i)
    351 	    if (known_prefixes[i] == *data)
    352 	      break;
    353 	  if (i == nknown_prefixes)
    354 	    break;
    355 
    356 	  prefixes |= last_prefix_bit = 1 << i;
    357 
    358 	  ++data;
    359 	}
    360 
    361 #ifdef X86_64
    362       if (data < end && (*data & 0xf0) == 0x40)
    363 	prefixes |= ((*data++) & 0xf) | has_rex;
    364 #endif
    365 
    366       bufcnt = 0;
    367       size_t cnt = 0;
    368 
    369       const uint8_t *curr = match_data;
    370       const uint8_t *const match_end = match_data + sizeof (match_data);
    371 
    372       assert (data <= end);
    373       if (data == end)
    374 	{
    375 	  if (prefixes != 0)
    376 	    goto print_prefix;
    377 
    378 	  retval = -1;
    379 	  goto do_ret;
    380 	}
    381 
    382     next_match:
    383       while (curr < match_end)
    384 	{
    385 	  uint_fast8_t len = *curr++;
    386 	  uint_fast8_t clen = len >> 4;
    387 	  len &= 0xf;
    388 	  const uint8_t *next_curr = curr + clen + (len - clen) * 2;
    389 
    390 	  assert (len > 0);
    391 	  assert (curr + clen + 2 * (len - clen) <= match_end);
    392 
    393 	  const uint8_t *codep = data;
    394 	  int correct_prefix = 0;
    395 	  int opoff = 0;
    396 
    397 	  if (data > begin && codep[-1] == *curr && clen > 0)
    398 	    {
    399 	      /* We match a prefix byte.  This is exactly one byte and
    400 		 is matched exactly, without a mask.  */
    401 	      --len;
    402 	      --clen;
    403 	      opoff = 8;
    404 
    405 	      ++curr;
    406 
    407 	      assert (last_prefix_bit != 0);
    408 	      correct_prefix = last_prefix_bit;
    409 	    }
    410 
    411 	  size_t avail = len;
    412 	  while (clen > 0)
    413 	    {
    414 	      if (*codep++ != *curr++)
    415 		goto not;
    416 	      --avail;
    417 	      --clen;
    418 	      if (codep == end && avail > 0)
    419 		goto do_ret;
    420 	    }
    421 
    422 	  while (avail > 0)
    423 	    {
    424 	      uint_fast8_t masked = *codep++ & *curr++;
    425 	      if (masked != *curr++)
    426 		{
    427 		not:
    428 		  curr = next_curr;
    429 		  ++cnt;
    430 		  bufcnt = 0;
    431 		  goto next_match;
    432 		}
    433 
    434 	      --avail;
    435 	      if (codep == end && avail > 0)
    436 		goto do_ret;
    437 	    }
    438 
    439 	  if (len > end - data)
    440 	    /* There is not enough data for the entire instruction.  The
    441 	       caller can figure this out by looking at the pointer into
    442 	       the input data.  */
    443 	    goto do_ret;
    444 
    445 	  assert (correct_prefix == 0
    446 		  || (prefixes & correct_prefix) != 0);
    447 	  prefixes ^= correct_prefix;
    448 
    449 	  if (0)
    450 	    {
    451 	      /* Resize the buffer.  */
    452 	      char *oldbuf;
    453 	    enomem:
    454 	      oldbuf = buf;
    455 	      if (buf == initbuf)
    456 		buf = malloc (2 * bufsize);
    457 	      else
    458 		buf = realloc (buf, 2 * bufsize);
    459 	      if (buf == NULL)
    460 		{
    461 		  buf = oldbuf;
    462 		  retval = ENOMEM;
    463 		  goto do_ret;
    464 		}
    465 	      bufsize *= 2;
    466 
    467 	      output_data.bufp = buf;
    468 	      output_data.bufsize = bufsize;
    469 	      bufcnt = 0;
    470 
    471 	      if (data == end)
    472 		{
    473 		  assert (prefixes != 0);
    474 		  goto print_prefix;
    475 		}
    476 
    477 	      /* gcc is not clever enough to see the following variables
    478 		 are not used uninitialized.  */
    479 	      asm (""
    480 		   : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
    481 		     "=mr" (next_curr), "=mr" (len));
    482 	    }
    483 
    484 	  size_t prefix_size = 0;
    485 
    486 	  // XXXonly print as prefix if valid?
    487 	  if ((prefixes & has_lock) != 0)
    488 	    {
    489 	      ADD_STRING ("lock ");
    490 	      prefix_size += 5;
    491 	    }
    492 
    493 	  if (instrtab[cnt].rep)
    494 	    {
    495 	      if ((prefixes & has_rep) !=  0)
    496 		{
    497 		  ADD_STRING ("rep ");
    498 		  prefix_size += 4;
    499 		}
    500 	    }
    501 	  else if (instrtab[cnt].repe
    502 		   && (prefixes & (has_rep | has_repne)) != 0)
    503 	    {
    504 	      if ((prefixes & has_repne) != 0)
    505 		{
    506 		  ADD_STRING ("repne ");
    507 		  prefix_size += 6;
    508 		}
    509 	      else if ((prefixes & has_rep) != 0)
    510 		{
    511 		  ADD_STRING ("repe ");
    512 		  prefix_size += 5;
    513 		}
    514 	    }
    515 	  else if ((prefixes & (has_rep | has_repne)) != 0)
    516 	    {
    517 	      uint_fast8_t byte;
    518 	    print_prefix:
    519 	      bufcnt = 0;
    520 	      byte = *begin;
    521 	      /* This is a prefix byte.  Print it.  */
    522 	      switch (byte)
    523 		{
    524 		case prefix_rep:
    525 		  ADD_STRING ("rep");
    526 		  break;
    527 		case prefix_repne:
    528 		  ADD_STRING ("repne");
    529 		  break;
    530 		case prefix_cs:
    531 		  ADD_STRING ("cs");
    532 		  break;
    533 		case prefix_ds:
    534 		  ADD_STRING ("ds");
    535 		  break;
    536 		case prefix_es:
    537 		  ADD_STRING ("es");
    538 		  break;
    539 		case prefix_fs:
    540 		  ADD_STRING ("fs");
    541 		  break;
    542 		case prefix_gs:
    543 		  ADD_STRING ("gs");
    544 		  break;
    545 		case prefix_ss:
    546 		  ADD_STRING ("ss");
    547 		  break;
    548 		case prefix_data16:
    549 		  ADD_STRING ("data16");
    550 		  break;
    551 		case prefix_addr16:
    552 		  ADD_STRING ("addr16");
    553 		  break;
    554 		case prefix_lock:
    555 		  ADD_STRING ("lock");
    556 		  break;
    557 #ifdef X86_64
    558 		case 0x40 ... 0x4f:
    559 		  ADD_STRING ("rex");
    560 		  if (byte != 0x40)
    561 		    {
    562 		      ADD_CHAR ('.');
    563 		      if (byte & 0x8)
    564 			ADD_CHAR ('w');
    565 		      if (byte & 0x4)
    566 			ADD_CHAR ('r');
    567 		      if (byte & 0x3)
    568 			ADD_CHAR ('x');
    569 		      if (byte & 0x1)
    570 			ADD_CHAR ('b');
    571 		    }
    572 		  break;
    573 #endif
    574 		default:
    575 		  /* Cannot happen.  */
    576 		  puts ("unknown prefix");
    577 		  abort ();
    578 		}
    579 	      data = begin + 1;
    580 	      ++addr;
    581 
    582 	      goto out;
    583 	    }
    584 
    585 	  /* We have a match.  First determine how many bytes are
    586 	     needed for the adressing mode.  */
    587 	  param_start = codep;
    588 	  if (instrtab[cnt].modrm)
    589 	    {
    590 	      uint_fast8_t modrm = codep[-1];
    591 
    592 #ifndef X86_64
    593 	      if (likely ((prefixes & has_addr16) != 0))
    594 		{
    595 		  /* Account for displacement.  */
    596 		  if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
    597 		    param_start += 2;
    598 		  else if ((modrm & 0xc0) == 0x40)
    599 		    param_start += 1;
    600 		}
    601 	      else
    602 #endif
    603 		{
    604 		  /* Account for SIB.  */
    605 		  if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
    606 		    param_start += 1;
    607 
    608 		  /* Account for displacement.  */
    609 		  if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
    610 		      || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
    611 		    param_start += 4;
    612 		  else if ((modrm & 0xc0) == 0x40)
    613 		    param_start += 1;
    614 		}
    615 
    616 	      if (unlikely (param_start > end))
    617 		goto not;
    618 	    }
    619 
    620 	  output_data.addr = addr + (data - begin);
    621 	  output_data.data = data;
    622 
    623 	  unsigned long string_end_idx = 0;
    624 	  fmt = save_fmt;
    625 	  const char *deferred_start = NULL;
    626 	  size_t deferred_len = 0;
    627 	  // XXX Can we get this from color.c?
    628 	  static const char color_off[] = "\e[0m";
    629 	  while (*fmt != '\0')
    630 	    {
    631 	      if (*fmt != '%')
    632 		{
    633 		  char ch = *fmt++;
    634 		  if (ch == '\\')
    635 		    {
    636 		      switch ((ch = *fmt++))
    637 			{
    638 			case '0' ... '7':
    639 			  {
    640 			    int val = ch - '0';
    641 			    ch = *fmt;
    642 			    if (ch >= '0' && ch <= '7')
    643 			      {
    644 				val *= 8;
    645 				val += ch - '0';
    646 				ch = *++fmt;
    647 				if (ch >= '0' && ch <= '7' && val < 32)
    648 				  {
    649 				    val *= 8;
    650 				    val += ch - '0';
    651 				    ++fmt;
    652 				  }
    653 			      }
    654 			    ch = val;
    655 			  }
    656 			  break;
    657 
    658 			case 'n':
    659 			  ch = '\n';
    660 			  break;
    661 
    662 			case 't':
    663 			  ch = '\t';
    664 			  break;
    665 
    666 			default:
    667 			  retval = EINVAL;
    668 			  goto do_ret;
    669 			}
    670 		    }
    671 		  else if (ch == '\e' && *fmt == '[')
    672 		    {
    673 		      deferred_start = fmt - 1;
    674 		      do
    675 			++fmt;
    676 		      while (*fmt != 'm' && *fmt != '\0');
    677 
    678 		      if (*fmt == 'm')
    679 			{
    680 			  deferred_len = ++fmt - deferred_start;
    681 			  continue;
    682 			}
    683 
    684 		      fmt = deferred_start + 1;
    685 		      deferred_start = NULL;
    686 		    }
    687 		  ADD_CHAR (ch);
    688 		  continue;
    689 		}
    690 	      ++fmt;
    691 
    692 	      int width = 0;
    693 	      while (isdigit (*fmt))
    694 		width = width * 10 + (*fmt++ - '0');
    695 
    696 	      int prec = 0;
    697 	      if (*fmt == '.')
    698 		while (isdigit (*++fmt))
    699 		  prec = prec * 10 + (*fmt - '0');
    700 
    701 	      size_t start_idx = bufcnt;
    702 	      size_t non_printing = 0;
    703 	      switch (*fmt++)
    704 		{
    705 		  char mnebuf[16];
    706 		  const char *str;
    707 
    708 		case 'm':
    709 		  /* Mnemonic.  */
    710 
    711 		  if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
    712 		    {
    713 		      switch (*data)
    714 			{
    715 #ifdef X86_64
    716 			case 0x90:
    717 			  if (prefixes & has_rex_b)
    718 			    goto not;
    719 			  str = "nop";
    720 			  break;
    721 #endif
    722 
    723 			case 0x98:
    724 #ifdef X86_64
    725 			  if (prefixes == (has_rex_w | has_rex))
    726 			    {
    727 			      str = "cltq";
    728 			      break;
    729 			    }
    730 #endif
    731 			  if (prefixes & ~has_data16)
    732 			    goto print_prefix;
    733 			  str = prefixes & has_data16 ? "cbtw" : "cwtl";
    734 			  break;
    735 
    736 			case 0x99:
    737 #ifdef X86_64
    738 			  if (prefixes == (has_rex_w | has_rex))
    739 			    {
    740 			      str = "cqto";
    741 			      break;
    742 			    }
    743 #endif
    744 			  if (prefixes & ~has_data16)
    745 			    goto print_prefix;
    746 			  str = prefixes & has_data16 ? "cwtd" : "cltd";
    747 			  break;
    748 
    749 			case 0xe3:
    750 			  if (prefixes & ~has_addr16)
    751 			    goto print_prefix;
    752 #ifdef X86_64
    753 			  str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
    754 #else
    755 			  str = prefixes & has_addr16 ? "jcxz" : "jecxz";
    756 #endif
    757 			  break;
    758 
    759 			case 0x0f:
    760 			  if (data[1] == 0x0f)
    761 			    {
    762 			      /* AMD 3DNOW.  We need one more byte.  */
    763 			      if (param_start >= end)
    764 				goto not;
    765 			      if (*param_start < AMD3DNOW_LOW_IDX
    766 				  || *param_start > AMD3DNOW_HIGH_IDX)
    767 				goto not;
    768 			      unsigned int idx
    769 				= amd3dnow[AMD3DNOW_IDX (*param_start)];
    770 			      if (idx == 0)
    771 				goto not;
    772 			      str = amd3dnowstr + idx - 1;
    773 			      /* Eat the immediate byte indicating the
    774 				 operation.  */
    775 			      ++param_start;
    776 			      break;
    777 			    }
    778 #ifdef X86_64
    779 			  if (data[1] == 0xc7)
    780 			    {
    781 			      str = ((prefixes & has_rex_w)
    782 				     ? "cmpxchg16b" : "cmpxchg8b");
    783 			      break;
    784 			    }
    785 #endif
    786 			  if (data[1] == 0xc2)
    787 			    {
    788 			      if (param_start >= end)
    789 				goto not;
    790 			      if (*param_start > 7)
    791 				goto not;
    792 			      static const char cmpops[][9] =
    793 				{
    794 				  [0] = "cmpeq",
    795 				  [1] = "cmplt",
    796 				  [2] = "cmple",
    797 				  [3] = "cmpunord",
    798 				  [4] = "cmpneq",
    799 				  [5] = "cmpnlt",
    800 				  [6] = "cmpnle",
    801 				  [7] = "cmpord"
    802 				};
    803 			      char *cp = stpcpy (mnebuf, cmpops[*param_start]);
    804 			      if (correct_prefix & (has_rep | has_repne))
    805 				*cp++ = 's';
    806 			      else
    807 				*cp++ = 'p';
    808 			      if (correct_prefix & (has_data16 | has_repne))
    809 				*cp++ = 'd';
    810 			      else
    811 				*cp++ = 's';
    812 			      *cp = '\0';
    813 			      str = mnebuf;
    814 			      /* Eat the immediate byte indicating the
    815 				 operation.  */
    816 			      ++param_start;
    817 			      break;
    818 			    }
    819 
    820 			default:
    821 			  assert (! "INVALID not handled");
    822 			}
    823 		    }
    824 		  else
    825 		    str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
    826 
    827 		  if (deferred_start != NULL)
    828 		    {
    829 		      ADD_NSTRING (deferred_start, deferred_len);
    830 		      non_printing += deferred_len;
    831 		    }
    832 
    833 		  ADD_STRING (str);
    834 
    835 		  switch (instrtab[cnt].suffix)
    836 		    {
    837 		    case suffix_none:
    838 		      break;
    839 
    840 		    case suffix_w:
    841 		      if ((codep[-1] & 0xc0) != 0xc0)
    842 			{
    843 			  char ch;
    844 
    845 			  if (data[0] & 1)
    846 			    {
    847 			      if (prefixes & has_data16)
    848 				ch = 'w';
    849 #ifdef X86_64
    850 			      else if (prefixes & has_rex_w)
    851 				ch = 'q';
    852 #endif
    853 			      else
    854 				ch = 'l';
    855 			    }
    856 			  else
    857 			    ch = 'b';
    858 
    859 			  ADD_CHAR (ch);
    860 			}
    861 		      break;
    862 
    863 		    case suffix_w0:
    864 		      if ((codep[-1] & 0xc0) != 0xc0)
    865 			ADD_CHAR ('l');
    866 		      break;
    867 
    868 		    case suffix_w1:
    869 		      if ((data[0] & 0x4) == 0)
    870 			ADD_CHAR ('l');
    871 		      break;
    872 
    873 		    case suffix_W:
    874 		      if (prefixes & has_data16)
    875 			{
    876 			  ADD_CHAR ('w');
    877 			  prefixes &= ~has_data16;
    878 			}
    879 #ifdef X86_64
    880 		      else
    881 			ADD_CHAR ('q');
    882 #endif
    883 		      break;
    884 
    885 		    case suffix_W1:
    886 		      if (prefixes & has_data16)
    887 			{
    888 			  ADD_CHAR ('w');
    889 			  prefixes &= ~has_data16;
    890 			}
    891 #ifdef X86_64
    892 		      else if (prefixes & has_rex_w)
    893 			ADD_CHAR ('q');
    894 #endif
    895 		      break;
    896 
    897 		    case suffix_tttn:;
    898 		      static const char tttn[16][3] =
    899 			{
    900 			  "o", "no", "b", "ae", "e", "ne", "be", "a",
    901 			  "s", "ns", "p", "np", "l", "ge", "le", "g"
    902 			};
    903 		      ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
    904 		      break;
    905 
    906 		    case suffix_D:
    907 		      if ((codep[-1] & 0xc0) != 0xc0)
    908 			ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
    909 		      break;
    910 
    911 		    default:
    912 		      printf("unknown suffix %d\n", instrtab[cnt].suffix);
    913 		      abort ();
    914 		    }
    915 
    916 		  if (deferred_start != NULL)
    917 		    {
    918 		      ADD_STRING (color_off);
    919 		      non_printing += strlen (color_off);
    920 		    }
    921 
    922 		  string_end_idx = bufcnt;
    923 		  break;
    924 
    925 		case 'o':
    926 		  if (prec == 1 && instrtab[cnt].fct1 != 0)
    927 		    {
    928 		      /* First parameter.  */
    929 		      if (deferred_start != NULL)
    930 			{
    931 			  ADD_NSTRING (deferred_start, deferred_len);
    932 			  non_printing += deferred_len;
    933 			}
    934 
    935 		      if (instrtab[cnt].str1 != 0)
    936 			ADD_STRING (op1_str
    937 				    + op1_str_idx[instrtab[cnt].str1 - 1]);
    938 
    939 		      output_data.opoff1 = (instrtab[cnt].off1_1
    940 					    + OFF1_1_BIAS - opoff);
    941 		      output_data.opoff2 = (instrtab[cnt].off1_2
    942 					    + OFF1_2_BIAS - opoff);
    943 		      output_data.opoff3 = (instrtab[cnt].off1_3
    944 					    + OFF1_3_BIAS - opoff);
    945 		      int r = op1_fct[instrtab[cnt].fct1] (&output_data);
    946 		      if (r < 0)
    947 			goto not;
    948 		      if (r > 0)
    949 			goto enomem;
    950 
    951 		      if (deferred_start != NULL)
    952 			{
    953 			  ADD_STRING (color_off);
    954 			  non_printing += strlen (color_off);
    955 			}
    956 
    957 		      string_end_idx = bufcnt;
    958 		    }
    959 		  else if (prec == 2 && instrtab[cnt].fct2 != 0)
    960 		    {
    961 		      /* Second parameter.  */
    962 		      if (deferred_start != NULL)
    963 			{
    964 			  ADD_NSTRING (deferred_start, deferred_len);
    965 			  non_printing += deferred_len;
    966 			}
    967 
    968 		      if (instrtab[cnt].str2 != 0)
    969 			ADD_STRING (op2_str
    970 				    + op2_str_idx[instrtab[cnt].str2 - 1]);
    971 
    972 		      output_data.opoff1 = (instrtab[cnt].off2_1
    973 					    + OFF2_1_BIAS - opoff);
    974 		      output_data.opoff2 = (instrtab[cnt].off2_2
    975 					    + OFF2_2_BIAS - opoff);
    976 		      output_data.opoff3 = (instrtab[cnt].off2_3
    977 					    + OFF2_3_BIAS - opoff);
    978 		      int r = op2_fct[instrtab[cnt].fct2] (&output_data);
    979 		      if (r < 0)
    980 			goto not;
    981 		      if (r > 0)
    982 			goto enomem;
    983 
    984 		      if (deferred_start != NULL)
    985 			{
    986 			  ADD_STRING (color_off);
    987 			  non_printing += strlen (color_off);
    988 			}
    989 
    990 		      string_end_idx = bufcnt;
    991 		    }
    992 		  else if (prec == 3 && instrtab[cnt].fct3 != 0)
    993 		    {
    994 		      /* Third parameter.  */
    995 		      if (deferred_start != NULL)
    996 			{
    997 			  ADD_NSTRING (deferred_start, deferred_len);
    998 			  non_printing += deferred_len;
    999 			}
   1000 
   1001 		      if (instrtab[cnt].str3 != 0)
   1002 			ADD_STRING (op3_str
   1003 				    + op3_str_idx[instrtab[cnt].str3 - 1]);
   1004 
   1005 		      output_data.opoff1 = (instrtab[cnt].off3_1
   1006 					    + OFF3_1_BIAS - opoff);
   1007 		      output_data.opoff2 = (instrtab[cnt].off3_2
   1008 					    + OFF3_2_BIAS - opoff);
   1009 #ifdef OFF3_3_BITS
   1010 		      output_data.opoff3 = (instrtab[cnt].off3_3
   1011 					    + OFF3_3_BIAS - opoff);
   1012 #else
   1013 		      output_data.opoff3 = 0;
   1014 #endif
   1015 		      int r = op3_fct[instrtab[cnt].fct3] (&output_data);
   1016 		      if (r < 0)
   1017 			goto not;
   1018 		      if (r > 0)
   1019 			goto enomem;
   1020 
   1021 		      if (deferred_start != NULL)
   1022 			{
   1023 			  ADD_STRING (color_off);
   1024 			  non_printing += strlen (color_off);
   1025 			}
   1026 
   1027 		      string_end_idx = bufcnt;
   1028 		    }
   1029 		  else
   1030 		    bufcnt = string_end_idx;
   1031 		  break;
   1032 
   1033 		case 'e':
   1034 		  string_end_idx = bufcnt;
   1035 		  break;
   1036 
   1037 		case 'a':
   1038 		  /* Pad to requested column.  */
   1039 		  while (bufcnt - non_printing < (size_t) width)
   1040 		    ADD_CHAR (' ');
   1041 		  width = 0;
   1042 		  break;
   1043 
   1044 		case 'l':
   1045 		  if (deferred_start != NULL)
   1046 		    {
   1047 		      ADD_NSTRING (deferred_start, deferred_len);
   1048 		      non_printing += deferred_len;
   1049 		    }
   1050 
   1051 		  if (output_data.labelbuf != NULL
   1052 		      && output_data.labelbuf[0] != '\0')
   1053 		    {
   1054 		      ADD_STRING (output_data.labelbuf);
   1055 		      output_data.labelbuf[0] = '\0';
   1056 		      string_end_idx = bufcnt;
   1057 		    }
   1058 		  else if (output_data.symaddr_use != addr_none)
   1059 		    {
   1060 		      GElf_Addr symaddr = output_data.symaddr;
   1061 		      if (output_data.symaddr_use >= addr_rel_symbolic)
   1062 			symaddr += addr + param_start - begin;
   1063 
   1064 		      // XXX Lookup symbol based on symaddr
   1065 		      const char *symstr = NULL;
   1066 		      if (symcb != NULL
   1067 			  && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
   1068 				    &output_data.labelbuf,
   1069 				    &output_data.labelbufsize, symcbarg) == 0)
   1070 			symstr = output_data.labelbuf;
   1071 
   1072 		      size_t bufavail = bufsize - bufcnt;
   1073 		      int r = 0;
   1074 		      if (symstr != NULL)
   1075 			r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
   1076 				      symstr);
   1077 		      else if (output_data.symaddr_use == addr_abs_always
   1078 			       || output_data.symaddr_use == addr_rel_always)
   1079 			r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
   1080 				      (uint64_t) symaddr);
   1081 
   1082 		      assert (r >= 0);
   1083 		      if ((size_t) r >= bufavail)
   1084 			goto enomem;
   1085 		      bufcnt += r;
   1086 		      string_end_idx = bufcnt;
   1087 
   1088 		      output_data.symaddr_use = addr_none;
   1089 		    }
   1090 		  if (deferred_start != NULL)
   1091 		    {
   1092 		      ADD_STRING (color_off);
   1093 		      non_printing += strlen (color_off);
   1094 		    }
   1095 		  break;
   1096 
   1097 		default:
   1098 		  abort ();
   1099 		}
   1100 
   1101 	      deferred_start = NULL;
   1102 
   1103 	      /* Pad according to the specified width.  */
   1104 	      while (bufcnt + prefix_size - non_printing < start_idx + width)
   1105 		ADD_CHAR (' ');
   1106 	      prefix_size = 0;
   1107 	    }
   1108 
   1109 	  if ((prefixes & SEGMENT_PREFIXES) != 0)
   1110 	    goto print_prefix;
   1111 
   1112 	  assert (string_end_idx != ~0ul);
   1113 	  bufcnt = string_end_idx;
   1114 
   1115 	  addr += param_start - begin;
   1116 	  data = param_start;
   1117 
   1118 	  goto out;
   1119 	}
   1120 
   1121       /* Invalid (or at least unhandled) opcode.  */
   1122       if (prefixes != 0)
   1123 	goto print_prefix;
   1124       assert (*startp == data);
   1125       ++data;
   1126       ADD_STRING ("(bad)");
   1127       addr += data - begin;
   1128 
   1129     out:
   1130       if (bufcnt == bufsize)
   1131 	goto enomem;
   1132       buf[bufcnt] = '\0';
   1133 
   1134       *startp = data;
   1135       retval = outcb (buf, bufcnt, outcbarg);
   1136       if (retval != 0)
   1137 	goto do_ret;
   1138     }
   1139 
   1140  do_ret:
   1141   free (output_data.labelbuf);
   1142   if (buf != initbuf)
   1143     free (buf);
   1144 
   1145   return retval;
   1146 }
   1147