LCOV - code coverage report
Current view: top level - libcpu - i386_disasm.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 280 382 73.3 %
Date: 2017-01-05 09:15:16 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12