Blame libcpu/i386_disasm.c

Packit Service 97d2fb
/* Disassembler for x86.
Packit Service 97d2fb
   Copyright (C) 2007, 2008, 2009, 2011 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2007.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <config.h>
Packit Service 97d2fb
#include <ctype.h>
Packit Service 97d2fb
#include <endian.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <gelf.h>
Packit Service 97d2fb
#include <stddef.h>
Packit Service 97d2fb
#include <stdint.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include "../libebl/libeblP.h"
Packit Service 97d2fb
Packit Service 97d2fb
#define MACHINE_ENCODING __LITTLE_ENDIAN
Packit Service 97d2fb
#include "memory-access.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#ifndef MNEFILE
Packit Service 97d2fb
# define MNEFILE "i386.mnemonics"
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#define MNESTRFIELD(line) MNESTRFIELD1 (line)
Packit Service 97d2fb
#define MNESTRFIELD1(line) str##line
Packit Service 97d2fb
static const union mnestr_t
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct
Packit Service 97d2fb
  {
Packit Service 97d2fb
#define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)];
Packit Service 97d2fb
#include MNEFILE
Packit Service 97d2fb
#undef MNE
Packit Service 97d2fb
  };
Packit Service 97d2fb
  char str[0];
Packit Service 97d2fb
} mnestr =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    {
Packit Service 97d2fb
#define MNE(name) #name,
Packit Service 97d2fb
#include MNEFILE
Packit Service 97d2fb
#undef MNE
Packit Service 97d2fb
    }
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
/* The index can be stored in the instrtab.  */
Packit Service 97d2fb
enum
Packit Service 97d2fb
  {
Packit Service 97d2fb
#define MNE(name) MNE_##name,
Packit Service 97d2fb
#include MNEFILE
Packit Service 97d2fb
#undef MNE
Packit Service 97d2fb
    MNE_INVALID
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
static const unsigned short int mneidx[] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
#define MNE(name) \
Packit Service 97d2fb
  [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)),
Packit Service 97d2fb
#include MNEFILE
Packit Service 97d2fb
#undef MNE
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
enum
Packit Service 97d2fb
  {
Packit Service 97d2fb
    idx_rex_b = 0,
Packit Service 97d2fb
    idx_rex_x,
Packit Service 97d2fb
    idx_rex_r,
Packit Service 97d2fb
    idx_rex_w,
Packit Service 97d2fb
    idx_rex,
Packit Service 97d2fb
    idx_cs,
Packit Service 97d2fb
    idx_ds,
Packit Service 97d2fb
    idx_es,
Packit Service 97d2fb
    idx_fs,
Packit Service 97d2fb
    idx_gs,
Packit Service 97d2fb
    idx_ss,
Packit Service 97d2fb
    idx_data16,
Packit Service 97d2fb
    idx_addr16,
Packit Service 97d2fb
    idx_rep,
Packit Service 97d2fb
    idx_repne,
Packit Service 97d2fb
    idx_lock
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
enum
Packit Service 97d2fb
  {
Packit Service 97d2fb
#define prefbit(pref) has_##pref = 1 << idx_##pref
Packit Service 97d2fb
    prefbit (rex_b),
Packit Service 97d2fb
    prefbit (rex_x),
Packit Service 97d2fb
    prefbit (rex_r),
Packit Service 97d2fb
    prefbit (rex_w),
Packit Service 97d2fb
    prefbit (rex),
Packit Service 97d2fb
    prefbit (cs),
Packit Service 97d2fb
    prefbit (ds),
Packit Service 97d2fb
    prefbit (es),
Packit Service 97d2fb
    prefbit (fs),
Packit Service 97d2fb
    prefbit (gs),
Packit Service 97d2fb
    prefbit (ss),
Packit Service 97d2fb
    prefbit (data16),
Packit Service 97d2fb
    prefbit (addr16),
Packit Service 97d2fb
    prefbit (rep),
Packit Service 97d2fb
    prefbit (repne),
Packit Service 97d2fb
    prefbit (lock)
Packit Service 97d2fb
#undef prefbit
Packit Service 97d2fb
  };
Packit Service 97d2fb
#define SEGMENT_PREFIXES \
Packit Service 97d2fb
  (has_cs | has_ds | has_es | has_fs | has_gs | has_ss)
Packit Service 97d2fb
Packit Service 97d2fb
#define prefix_cs	0x2e
Packit Service 97d2fb
#define prefix_ds	0x3e
Packit Service 97d2fb
#define prefix_es	0x26
Packit Service 97d2fb
#define prefix_fs	0x64
Packit Service 97d2fb
#define prefix_gs	0x65
Packit Service 97d2fb
#define prefix_ss	0x36
Packit Service 97d2fb
#define prefix_data16	0x66
Packit Service 97d2fb
#define prefix_addr16	0x67
Packit Service 97d2fb
#define prefix_rep	0xf3
Packit Service 97d2fb
#define prefix_repne	0xf2
Packit Service 97d2fb
#define prefix_lock	0xf0
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static const uint8_t known_prefixes[] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
#define newpref(pref) [idx_##pref] = prefix_##pref
Packit Service 97d2fb
    newpref (cs),
Packit Service 97d2fb
    newpref (ds),
Packit Service 97d2fb
    newpref (es),
Packit Service 97d2fb
    newpref (fs),
Packit Service 97d2fb
    newpref (gs),
Packit Service 97d2fb
    newpref (ss),
Packit Service 97d2fb
    newpref (data16),
Packit Service 97d2fb
    newpref (addr16),
Packit Service 97d2fb
    newpref (rep),
Packit Service 97d2fb
    newpref (repne),
Packit Service 97d2fb
    newpref (lock)
Packit Service 97d2fb
#undef newpref
Packit Service 97d2fb
  };
Packit Service 97d2fb
#define nknown_prefixes (sizeof (known_prefixes) / sizeof (known_prefixes[0]))
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#if 0
Packit Service 97d2fb
static const char *prefix_str[] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
#define newpref(pref) [idx_##pref] = #pref
Packit Service 97d2fb
    newpref (cs),
Packit Service 97d2fb
    newpref (ds),
Packit Service 97d2fb
    newpref (es),
Packit Service 97d2fb
    newpref (fs),
Packit Service 97d2fb
    newpref (gs),
Packit Service 97d2fb
    newpref (ss),
Packit Service 97d2fb
    newpref (data16),
Packit Service 97d2fb
    newpref (addr16),
Packit Service 97d2fb
    newpref (rep),
Packit Service 97d2fb
    newpref (repne),
Packit Service 97d2fb
    newpref (lock)
Packit Service 97d2fb
#undef newpref
Packit Service 97d2fb
  };
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static const char amd3dnowstr[] =
Packit Service 97d2fb
#define MNE_3DNOW_PAVGUSB 1
Packit Service 97d2fb
  "pavgusb\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFADD (MNE_3DNOW_PAVGUSB + 8)
Packit Service 97d2fb
  "pfadd\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFSUB (MNE_3DNOW_PFADD + 6)
Packit Service 97d2fb
  "pfsub\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFSUBR (MNE_3DNOW_PFSUB + 6)
Packit Service 97d2fb
  "pfsubr\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFACC (MNE_3DNOW_PFSUBR + 7)
Packit Service 97d2fb
  "pfacc\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFCMPGE (MNE_3DNOW_PFACC + 6)
Packit Service 97d2fb
  "pfcmpge\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFCMPGT (MNE_3DNOW_PFCMPGE + 8)
Packit Service 97d2fb
  "pfcmpgt\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFCMPEQ (MNE_3DNOW_PFCMPGT + 8)
Packit Service 97d2fb
  "pfcmpeq\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFMIN (MNE_3DNOW_PFCMPEQ + 8)
Packit Service 97d2fb
  "pfmin\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFMAX (MNE_3DNOW_PFMIN + 6)
Packit Service 97d2fb
  "pfmax\0"
Packit Service 97d2fb
#define MNE_3DNOW_PI2FD (MNE_3DNOW_PFMAX + 6)
Packit Service 97d2fb
  "pi2fd\0"
Packit Service 97d2fb
#define MNE_3DNOW_PF2ID (MNE_3DNOW_PI2FD + 6)
Packit Service 97d2fb
  "pf2id\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFRCP (MNE_3DNOW_PF2ID + 6)
Packit Service 97d2fb
  "pfrcp\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFRSQRT (MNE_3DNOW_PFRCP + 6)
Packit Service 97d2fb
  "pfrsqrt\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFMUL (MNE_3DNOW_PFRSQRT + 8)
Packit Service 97d2fb
  "pfmul\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFRCPIT1 (MNE_3DNOW_PFMUL + 6)
Packit Service 97d2fb
  "pfrcpit1\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFRSQIT1 (MNE_3DNOW_PFRCPIT1 + 9)
Packit Service 97d2fb
  "pfrsqit1\0"
Packit Service 97d2fb
#define MNE_3DNOW_PFRCPIT2 (MNE_3DNOW_PFRSQIT1 + 9)
Packit Service 97d2fb
  "pfrcpit2\0"
Packit Service 97d2fb
#define MNE_3DNOW_PMULHRW (MNE_3DNOW_PFRCPIT2 + 9)
Packit Service 97d2fb
  "pmulhrw";
Packit Service 97d2fb
Packit Service 97d2fb
#define AMD3DNOW_LOW_IDX 0x0d
Packit Service 97d2fb
#define AMD3DNOW_HIGH_IDX (sizeof (amd3dnow) + AMD3DNOW_LOW_IDX - 1)
Packit Service 97d2fb
#define AMD3DNOW_IDX(val) ((val) - AMD3DNOW_LOW_IDX)
Packit Service 97d2fb
static const unsigned char amd3dnow[] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xbf)] = MNE_3DNOW_PAVGUSB,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x9e)] = MNE_3DNOW_PFADD,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x9a)] = MNE_3DNOW_PFSUB,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xaa)] = MNE_3DNOW_PFSUBR,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xae)] = MNE_3DNOW_PFACC,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x90)] = MNE_3DNOW_PFCMPGE,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xa0)] = MNE_3DNOW_PFCMPGT,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xb0)] = MNE_3DNOW_PFCMPEQ,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x94)] = MNE_3DNOW_PFMIN,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xa4)] = MNE_3DNOW_PFMAX,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x0d)] = MNE_3DNOW_PI2FD,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x1d)] = MNE_3DNOW_PF2ID,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x96)] = MNE_3DNOW_PFRCP,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0x97)] = MNE_3DNOW_PFRSQRT,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xb4)] = MNE_3DNOW_PFMUL,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xa6)] = MNE_3DNOW_PFRCPIT1,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xa7)] = MNE_3DNOW_PFRSQIT1,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xb6)] = MNE_3DNOW_PFRCPIT2,
Packit Service 97d2fb
    [AMD3DNOW_IDX (0xb7)] = MNE_3DNOW_PMULHRW
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
struct output_data
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Addr addr;
Packit Service 97d2fb
  int *prefixes;
Packit Service 97d2fb
  size_t opoff1;
Packit Service 97d2fb
  size_t opoff2;
Packit Service 97d2fb
  size_t opoff3;
Packit Service 97d2fb
  char *bufp;
Packit Service 97d2fb
  size_t *bufcntp;
Packit Service 97d2fb
  size_t bufsize;
Packit Service 97d2fb
  const uint8_t *data;
Packit Service 97d2fb
  const uint8_t **param_start;
Packit Service 97d2fb
  const uint8_t *end;
Packit Service 97d2fb
  char *labelbuf;
Packit Service 97d2fb
  size_t labelbufsize;
Packit Service 97d2fb
  enum
Packit Service 97d2fb
    {
Packit Service 97d2fb
      addr_none = 0,
Packit Service 97d2fb
      addr_abs_symbolic,
Packit Service 97d2fb
      addr_abs_always,
Packit Service 97d2fb
      addr_rel_symbolic,
Packit Service 97d2fb
      addr_rel_always
Packit Service 97d2fb
    } symaddr_use;
Packit Service 97d2fb
  GElf_Addr symaddr;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#ifndef DISFILE
Packit Service 97d2fb
# define DISFILE "i386_dis.h"
Packit Service 97d2fb
#endif
Packit Service 97d2fb
#include DISFILE
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#define ADD_CHAR(ch) \
Packit Service 97d2fb
  do {									      \
Packit Service 97d2fb
    if (unlikely (bufcnt == bufsize))					      \
Packit Service 97d2fb
      goto enomem;							      \
Packit Service 97d2fb
    buf[bufcnt++] = (ch);						      \
Packit Service 97d2fb
  } while (0)
Packit Service 97d2fb
Packit Service 97d2fb
#define ADD_STRING(str) \
Packit Service 97d2fb
  do {									      \
Packit Service 97d2fb
    const char *_str0 = (str);						      \
Packit Service 97d2fb
    size_t _len0 = strlen (_str0);					      \
Packit Service 97d2fb
    ADD_NSTRING (_str0, _len0);						      \
Packit Service 97d2fb
  } while (0)
Packit Service 97d2fb
Packit Service 97d2fb
#define ADD_NSTRING(str, len) \
Packit Service 97d2fb
  do {									      \
Packit Service 97d2fb
    const char *_str = (str);						      \
Packit Service 97d2fb
    size_t _len = (len);						      \
Packit Service 97d2fb
    if (unlikely (bufcnt + _len > bufsize))				      \
Packit Service 97d2fb
      goto enomem;							      \
Packit Service 97d2fb
    memcpy (buf + bufcnt, _str, _len);					      \
Packit Service 97d2fb
    bufcnt += _len;							      \
Packit Service 97d2fb
  } while (0)
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
i386_disasm (Ebl *ebl __attribute__((unused)),
Packit Service 97d2fb
	     const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
Packit Service 97d2fb
	     const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
Packit Service 97d2fb
	     void *outcbarg, void *symcbarg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *save_fmt = fmt;
Packit Service 97d2fb
Packit Service 97d2fb
#define BUFSIZE 512
Packit Service 97d2fb
  char initbuf[BUFSIZE];
Packit Service 97d2fb
  int prefixes;
Packit Service 97d2fb
  size_t bufcnt;
Packit Service 97d2fb
  size_t bufsize = BUFSIZE;
Packit Service 97d2fb
  char *buf = initbuf;
Packit Service 97d2fb
  const uint8_t *param_start;
Packit Service 97d2fb
Packit Service 97d2fb
  struct output_data output_data =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .prefixes = &prefixes,
Packit Service 97d2fb
      .bufp = buf,
Packit Service 97d2fb
      .bufsize = bufsize,
Packit Service 97d2fb
      .bufcntp = &bufcnt,
Packit Service 97d2fb
      .param_start = &param_start,
Packit Service 97d2fb
      .end = end
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
  int retval = 0;
Packit Service 97d2fb
  while (1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      prefixes = 0;
Packit Service 97d2fb
Packit Service 97d2fb
      const uint8_t *data = *startp;
Packit Service 97d2fb
      const uint8_t *begin = data;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Recognize all prefixes.  */
Packit Service 97d2fb
      int last_prefix_bit = 0;
Packit Service 97d2fb
      while (data < end)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  unsigned int i;
Packit Service 97d2fb
	  for (i = idx_cs; i < nknown_prefixes; ++i)
Packit Service 97d2fb
	    if (known_prefixes[i] == *data)
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	  if (i == nknown_prefixes)
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  prefixes |= last_prefix_bit = 1 << i;
Packit Service 97d2fb
Packit Service 97d2fb
	  ++data;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
      if (data < end && (*data & 0xf0) == 0x40)
Packit Service 97d2fb
	prefixes |= ((*data++) & 0xf) | has_rex;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
      bufcnt = 0;
Packit Service 97d2fb
      size_t cnt = 0;
Packit Service 97d2fb
Packit Service 97d2fb
      const uint8_t *curr = match_data;
Packit Service 97d2fb
      const uint8_t *const match_end = match_data + sizeof (match_data);
Packit Service 97d2fb
Packit Service 97d2fb
      assert (data <= end);
Packit Service 97d2fb
      if (data == end)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (prefixes != 0)
Packit Service 97d2fb
	    goto print_prefix;
Packit Service 97d2fb
Packit Service 97d2fb
	  retval = -1;
Packit Service 97d2fb
	  goto do_ret;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
    next_match:
Packit Service 97d2fb
      while (curr < match_end)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  uint_fast8_t len = *curr++;
Packit Service 97d2fb
	  uint_fast8_t clen = len >> 4;
Packit Service 97d2fb
	  len &= 0xf;
Packit Service 97d2fb
	  const uint8_t *next_curr = curr + clen + (len - clen) * 2;
Packit Service 97d2fb
Packit Service 97d2fb
	  assert (len > 0);
Packit Service 97d2fb
	  assert (curr + clen + 2 * (len - clen) <= match_end);
Packit Service 97d2fb
Packit Service 97d2fb
	  const uint8_t *codep = data;
Packit Service 97d2fb
	  int correct_prefix = 0;
Packit Service 97d2fb
	  int opoff = 0;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (data > begin && codep[-1] == *curr && clen > 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We match a prefix byte.  This is exactly one byte and
Packit Service 97d2fb
		 is matched exactly, without a mask.  */
Packit Service 97d2fb
	      --len;
Packit Service 97d2fb
	      --clen;
Packit Service 97d2fb
	      opoff = 8;
Packit Service 97d2fb
Packit Service 97d2fb
	      ++curr;
Packit Service 97d2fb
Packit Service 97d2fb
	      if (last_prefix_bit == 0)
Packit Service 97d2fb
		goto invalid_op;
Packit Service 97d2fb
	      correct_prefix = last_prefix_bit;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  size_t avail = len;
Packit Service 97d2fb
	  while (clen > 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (*codep++ != *curr++)
Packit Service 97d2fb
		goto not;
Packit Service 97d2fb
	      --avail;
Packit Service 97d2fb
	      --clen;
Packit Service 97d2fb
	      if (codep == end && avail > 0)
Packit Service 97d2fb
		goto do_ret;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  while (avail > 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      uint_fast8_t masked = *codep++ & *curr++;
Packit Service 97d2fb
	      if (masked != *curr++)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		not:
Packit Service 97d2fb
		  curr = next_curr;
Packit Service 97d2fb
		  ++cnt;
Packit Service 97d2fb
		  bufcnt = 0;
Packit Service 97d2fb
		  goto next_match;
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      --avail;
Packit Service 97d2fb
	      if (codep == end && avail > 0)
Packit Service 97d2fb
		goto do_ret;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (len > end - data)
Packit Service 97d2fb
	    /* There is not enough data for the entire instruction.  The
Packit Service 97d2fb
	       caller can figure this out by looking at the pointer into
Packit Service 97d2fb
	       the input data.  */
Packit Service 97d2fb
	    goto do_ret;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (correct_prefix != 0 && (prefixes & correct_prefix) == 0)
Packit Service 97d2fb
	    goto invalid_op;
Packit Service 97d2fb
	  prefixes ^= correct_prefix;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Resize the buffer.  */
Packit Service 97d2fb
	      char *oldbuf;
Packit Service 97d2fb
	    enomem:
Packit Service 97d2fb
	      oldbuf = buf;
Packit Service 97d2fb
	      if (buf == initbuf)
Packit Service 97d2fb
		buf = malloc (2 * bufsize);
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		buf = realloc (buf, 2 * bufsize);
Packit Service 97d2fb
	      if (buf == NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  buf = oldbuf;
Packit Service 97d2fb
		  retval = ENOMEM;
Packit Service 97d2fb
		  goto do_ret;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      bufsize *= 2;
Packit Service 97d2fb
Packit Service 97d2fb
	      output_data.bufp = buf;
Packit Service 97d2fb
	      output_data.bufsize = bufsize;
Packit Service 97d2fb
	      bufcnt = 0;
Packit Service 97d2fb
Packit Service 97d2fb
	      if (data == end)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  if (prefixes == 0)
Packit Service 97d2fb
		    goto invalid_op;
Packit Service 97d2fb
		  goto print_prefix;
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      /* gcc is not clever enough to see the following variables
Packit Service 97d2fb
		 are not used uninitialized.  */
Packit Service 97d2fb
	      asm (""
Packit Service 97d2fb
		   : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
Packit Service 97d2fb
		     "=mr" (next_curr), "=mr" (len));
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  size_t prefix_size = 0;
Packit Service 97d2fb
Packit Service 97d2fb
	  // XXXonly print as prefix if valid?
Packit Service 97d2fb
	  if ((prefixes & has_lock) != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      ADD_STRING ("lock ");
Packit Service 97d2fb
	      prefix_size += 5;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (instrtab[cnt].rep)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if ((prefixes & has_rep) !=  0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  ADD_STRING ("rep ");
Packit Service 97d2fb
		  prefix_size += 4;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else if (instrtab[cnt].repe
Packit Service 97d2fb
		   && (prefixes & (has_rep | has_repne)) != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if ((prefixes & has_repne) != 0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  ADD_STRING ("repne ");
Packit Service 97d2fb
		  prefix_size += 6;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      else if ((prefixes & has_rep) != 0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  ADD_STRING ("repe ");
Packit Service 97d2fb
		  prefix_size += 5;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else if ((prefixes & (has_rep | has_repne)) != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      uint_fast8_t byte;
Packit Service 97d2fb
	    print_prefix:
Packit Service 97d2fb
	      bufcnt = 0;
Packit Service 97d2fb
	      byte = *begin;
Packit Service 97d2fb
	      /* This is a prefix byte.  Print it.  */
Packit Service 97d2fb
	      switch (byte)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		case prefix_rep:
Packit Service 97d2fb
		  ADD_STRING ("rep");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_repne:
Packit Service 97d2fb
		  ADD_STRING ("repne");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_cs:
Packit Service 97d2fb
		  ADD_STRING ("cs");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_ds:
Packit Service 97d2fb
		  ADD_STRING ("ds");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_es:
Packit Service 97d2fb
		  ADD_STRING ("es");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_fs:
Packit Service 97d2fb
		  ADD_STRING ("fs");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_gs:
Packit Service 97d2fb
		  ADD_STRING ("gs");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_ss:
Packit Service 97d2fb
		  ADD_STRING ("ss");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_data16:
Packit Service 97d2fb
		  ADD_STRING ("data16");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_addr16:
Packit Service 97d2fb
		  ADD_STRING ("addr16");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		case prefix_lock:
Packit Service 97d2fb
		  ADD_STRING ("lock");
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
		case 0x40 ... 0x4f:
Packit Service 97d2fb
		  ADD_STRING ("rex");
Packit Service 97d2fb
		  if (byte != 0x40)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      ADD_CHAR ('.');
Packit Service 97d2fb
		      if (byte & 0x8)
Packit Service 97d2fb
			ADD_CHAR ('w');
Packit Service 97d2fb
		      if (byte & 0x4)
Packit Service 97d2fb
			ADD_CHAR ('r');
Packit Service 97d2fb
		      if (byte & 0x3)
Packit Service 97d2fb
			ADD_CHAR ('x');
Packit Service 97d2fb
		      if (byte & 0x1)
Packit Service 97d2fb
			ADD_CHAR ('b');
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
		default:
Packit Service 97d2fb
		  /* Cannot happen.  */
Packit Service 97d2fb
		  puts ("unknown prefix");
Packit Service 97d2fb
		  abort ();
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      data = begin + 1;
Packit Service 97d2fb
	      ++addr;
Packit Service 97d2fb
Packit Service 97d2fb
	      goto out;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* We have a match.  First determine how many bytes are
Packit Service 97d2fb
	     needed for the adressing mode.  */
Packit Service 97d2fb
	  param_start = codep;
Packit Service 97d2fb
	  if (instrtab[cnt].modrm)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      uint_fast8_t modrm = codep[-1];
Packit Service 97d2fb
Packit Service 97d2fb
#ifndef X86_64
Packit Service 97d2fb
	      if (likely ((prefixes & has_addr16) != 0))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* Account for displacement.  */
Packit Service 97d2fb
		  if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
Packit Service 97d2fb
		    param_start += 2;
Packit Service 97d2fb
		  else if ((modrm & 0xc0) == 0x40)
Packit Service 97d2fb
		    param_start += 1;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      else
Packit Service 97d2fb
#endif
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* Account for SIB.  */
Packit Service 97d2fb
		  if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
Packit Service 97d2fb
		    param_start += 1;
Packit Service 97d2fb
Packit Service 97d2fb
		  /* Account for displacement.  */
Packit Service 97d2fb
		  if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
Packit Service 97d2fb
		      || ((modrm & 0xc7) == 0x4
Packit Service 97d2fb
			  && param_start < end
Packit Service 97d2fb
			  && (codep[0] & 0x7) == 0x5))
Packit Service 97d2fb
		    param_start += 4;
Packit Service 97d2fb
		  else if ((modrm & 0xc0) == 0x40)
Packit Service 97d2fb
		    param_start += 1;
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      if (unlikely (param_start > end))
Packit Service 97d2fb
		goto not;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  output_data.addr = addr + (data - begin);
Packit Service 97d2fb
	  output_data.data = data;
Packit Service 97d2fb
Packit Service 97d2fb
	  unsigned long string_end_idx = 0;
Packit Service 97d2fb
	  fmt = save_fmt;
Packit Service 97d2fb
	  const char *deferred_start = NULL;
Packit Service 97d2fb
	  size_t deferred_len = 0;
Packit Service 97d2fb
	  // XXX Can we get this from color.c?
Packit Service 97d2fb
	  static const char color_off[] = "\e[0m";
Packit Service 97d2fb
	  while (*fmt != '\0')
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (*fmt != '%')
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  char ch = *fmt++;
Packit Service 97d2fb
		  if (ch == '\\')
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      switch ((ch = *fmt++))
Packit Service 97d2fb
			{
Packit Service 97d2fb
			case '0' ... '7':
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    int val = ch - '0';
Packit Service 97d2fb
			    ch = *fmt;
Packit Service 97d2fb
			    if (ch >= '0' && ch <= '7')
Packit Service 97d2fb
			      {
Packit Service 97d2fb
				val *= 8;
Packit Service 97d2fb
				val += ch - '0';
Packit Service 97d2fb
				ch = *++fmt;
Packit Service 97d2fb
				if (ch >= '0' && ch <= '7' && val < 32)
Packit Service 97d2fb
				  {
Packit Service 97d2fb
				    val *= 8;
Packit Service 97d2fb
				    val += ch - '0';
Packit Service 97d2fb
				    ++fmt;
Packit Service 97d2fb
				  }
Packit Service 97d2fb
			      }
Packit Service 97d2fb
			    ch = val;
Packit Service 97d2fb
			  }
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
Packit Service 97d2fb
			case 'n':
Packit Service 97d2fb
			  ch = '\n';
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
Packit Service 97d2fb
			case 't':
Packit Service 97d2fb
			  ch = '\t';
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
Packit Service 97d2fb
			default:
Packit Service 97d2fb
			  retval = EINVAL;
Packit Service 97d2fb
			  goto do_ret;
Packit Service 97d2fb
			}
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else if (ch == '\e' && *fmt == '[')
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      deferred_start = fmt - 1;
Packit Service 97d2fb
		      do
Packit Service 97d2fb
			++fmt;
Packit Service 97d2fb
		      while (*fmt != 'm' && *fmt != '\0');
Packit Service 97d2fb
Packit Service 97d2fb
		      if (*fmt == 'm')
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  deferred_len = ++fmt - deferred_start;
Packit Service 97d2fb
			  continue;
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      fmt = deferred_start + 1;
Packit Service 97d2fb
		      deferred_start = NULL;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  ADD_CHAR (ch);
Packit Service 97d2fb
		  continue;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      ++fmt;
Packit Service 97d2fb
Packit Service 97d2fb
	      int width = 0;
Packit Service 97d2fb
	      while (isdigit (*fmt))
Packit Service 97d2fb
		width = width * 10 + (*fmt++ - '0');
Packit Service 97d2fb
Packit Service 97d2fb
	      int prec = 0;
Packit Service 97d2fb
	      if (*fmt == '.')
Packit Service 97d2fb
		while (isdigit (*++fmt))
Packit Service 97d2fb
		  prec = prec * 10 + (*fmt - '0');
Packit Service 97d2fb
Packit Service 97d2fb
	      size_t start_idx = bufcnt;
Packit Service 97d2fb
	      size_t non_printing = 0;
Packit Service 97d2fb
	      switch (*fmt++)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  char mnebuf[16];
Packit Service 97d2fb
		  const char *str;
Packit Service 97d2fb
Packit Service 97d2fb
		case 'm':
Packit Service 97d2fb
		  /* Mnemonic.  */
Packit Service 97d2fb
Packit Service 97d2fb
		  if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      switch (*data)
Packit Service 97d2fb
			{
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
			case 0x90:
Packit Service 97d2fb
			  if (prefixes & has_rex_b)
Packit Service 97d2fb
			    goto not;
Packit Service 97d2fb
			  str = "nop";
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
			case 0x98:
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
			  if (prefixes == (has_rex_w | has_rex))
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      str = "cltq";
Packit Service 97d2fb
			      break;
Packit Service 97d2fb
			    }
Packit Service 97d2fb
#endif
Packit Service 97d2fb
			  if (prefixes & ~has_data16)
Packit Service 97d2fb
			    goto print_prefix;
Packit Service 97d2fb
			  str = prefixes & has_data16 ? "cbtw" : "cwtl";
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
Packit Service 97d2fb
			case 0x99:
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
			  if (prefixes == (has_rex_w | has_rex))
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      str = "cqto";
Packit Service 97d2fb
			      break;
Packit Service 97d2fb
			    }
Packit Service 97d2fb
#endif
Packit Service 97d2fb
			  if (prefixes & ~has_data16)
Packit Service 97d2fb
			    goto print_prefix;
Packit Service 97d2fb
			  str = prefixes & has_data16 ? "cwtd" : "cltd";
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
Packit Service 97d2fb
			case 0xe3:
Packit Service 97d2fb
			  if (prefixes & ~has_addr16)
Packit Service 97d2fb
			    goto print_prefix;
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
			  str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
Packit Service 97d2fb
#else
Packit Service 97d2fb
			  str = prefixes & has_addr16 ? "jcxz" : "jecxz";
Packit Service 97d2fb
#endif
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
Packit Service 97d2fb
			case 0x0f:
Packit Service 97d2fb
			  if (data[1] == 0x0f)
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      /* AMD 3DNOW.  We need one more byte.  */
Packit Service 97d2fb
			      if (param_start >= end)
Packit Service 97d2fb
				goto not;
Packit Service 97d2fb
			      if (*param_start < AMD3DNOW_LOW_IDX
Packit Service 97d2fb
				  || *param_start > AMD3DNOW_HIGH_IDX)
Packit Service 97d2fb
				goto not;
Packit Service 97d2fb
			      unsigned int idx
Packit Service 97d2fb
				= amd3dnow[AMD3DNOW_IDX (*param_start)];
Packit Service 97d2fb
			      if (idx == 0)
Packit Service 97d2fb
				goto not;
Packit Service 97d2fb
			      str = amd3dnowstr + idx - 1;
Packit Service 97d2fb
			      /* Eat the immediate byte indicating the
Packit Service 97d2fb
				 operation.  */
Packit Service 97d2fb
			      ++param_start;
Packit Service 97d2fb
			      break;
Packit Service 97d2fb
			    }
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
			  if (data[1] == 0xc7)
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      str = ((prefixes & has_rex_w)
Packit Service 97d2fb
				     ? "cmpxchg16b" : "cmpxchg8b");
Packit Service 97d2fb
			      break;
Packit Service 97d2fb
			    }
Packit Service 97d2fb
#endif
Packit Service 97d2fb
			  if (data[1] == 0xc2)
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      if (param_start >= end)
Packit Service 97d2fb
				goto not;
Packit Service 97d2fb
			      if (*param_start > 7)
Packit Service 97d2fb
				goto not;
Packit Service 97d2fb
			      static const char cmpops[][9] =
Packit Service 97d2fb
				{
Packit Service 97d2fb
				  [0] = "cmpeq",
Packit Service 97d2fb
				  [1] = "cmplt",
Packit Service 97d2fb
				  [2] = "cmple",
Packit Service 97d2fb
				  [3] = "cmpunord",
Packit Service 97d2fb
				  [4] = "cmpneq",
Packit Service 97d2fb
				  [5] = "cmpnlt",
Packit Service 97d2fb
				  [6] = "cmpnle",
Packit Service 97d2fb
				  [7] = "cmpord"
Packit Service 97d2fb
				};
Packit Service 97d2fb
			      char *cp = stpcpy (mnebuf, cmpops[*param_start]);
Packit Service 97d2fb
			      if (correct_prefix & (has_rep | has_repne))
Packit Service 97d2fb
				*cp++ = 's';
Packit Service 97d2fb
			      else
Packit Service 97d2fb
				*cp++ = 'p';
Packit Service 97d2fb
			      if (correct_prefix & (has_data16 | has_repne))
Packit Service 97d2fb
				*cp++ = 'd';
Packit Service 97d2fb
			      else
Packit Service 97d2fb
				*cp++ = 's';
Packit Service 97d2fb
			      *cp = '\0';
Packit Service 97d2fb
			      str = mnebuf;
Packit Service 97d2fb
			      /* Eat the immediate byte indicating the
Packit Service 97d2fb
				 operation.  */
Packit Service 97d2fb
			      ++param_start;
Packit Service 97d2fb
			      break;
Packit Service 97d2fb
			    }
Packit Service 97d2fb
			  FALLTHROUGH;
Packit Service 97d2fb
			default:
Packit Service 97d2fb
			  str = "INVALID not handled";
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
			}
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
Packit Service 97d2fb
Packit Service 97d2fb
		  if (deferred_start != NULL)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      ADD_NSTRING (deferred_start, deferred_len);
Packit Service 97d2fb
		      non_printing += deferred_len;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  ADD_STRING (str);
Packit Service 97d2fb
Packit Service 97d2fb
		  switch (instrtab[cnt].suffix)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		    case suffix_none:
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    case suffix_w:
Packit Service 97d2fb
		      if ((codep[-1] & 0xc0) != 0xc0)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  char ch;
Packit Service 97d2fb
Packit Service 97d2fb
			  if (data[0] & 1)
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      if (prefixes & has_data16)
Packit Service 97d2fb
				ch = 'w';
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
			      else if (prefixes & has_rex_w)
Packit Service 97d2fb
				ch = 'q';
Packit Service 97d2fb
#endif
Packit Service 97d2fb
			      else
Packit Service 97d2fb
				ch = 'l';
Packit Service 97d2fb
			    }
Packit Service 97d2fb
			  else
Packit Service 97d2fb
			    ch = 'b';
Packit Service 97d2fb
Packit Service 97d2fb
			  ADD_CHAR (ch);
Packit Service 97d2fb
			}
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    case suffix_w0:
Packit Service 97d2fb
		      if ((codep[-1] & 0xc0) != 0xc0)
Packit Service 97d2fb
			ADD_CHAR ('l');
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    case suffix_w1:
Packit Service 97d2fb
		      if ((data[0] & 0x4) == 0)
Packit Service 97d2fb
			ADD_CHAR ('l');
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    case suffix_W:
Packit Service 97d2fb
		      if (prefixes & has_data16)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_CHAR ('w');
Packit Service 97d2fb
			  prefixes &= ~has_data16;
Packit Service 97d2fb
			}
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
		      else
Packit Service 97d2fb
			ADD_CHAR ('q');
Packit Service 97d2fb
#endif
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    case suffix_W1:
Packit Service 97d2fb
		      if (prefixes & has_data16)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_CHAR ('w');
Packit Service 97d2fb
			  prefixes &= ~has_data16;
Packit Service 97d2fb
			}
Packit Service 97d2fb
#ifdef X86_64
Packit Service 97d2fb
		      else if (prefixes & has_rex_w)
Packit Service 97d2fb
			ADD_CHAR ('q');
Packit Service 97d2fb
#endif
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    case suffix_tttn:;
Packit Service 97d2fb
		      static const char tttn[16][3] =
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  "o", "no", "b", "ae", "e", "ne", "be", "a",
Packit Service 97d2fb
			  "s", "ns", "p", "np", "l", "ge", "le", "g"
Packit Service 97d2fb
			};
Packit Service 97d2fb
		      ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    case suffix_D:
Packit Service 97d2fb
		      if ((codep[-1] & 0xc0) != 0xc0)
Packit Service 97d2fb
			ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
Packit Service 97d2fb
		    default:
Packit Service 97d2fb
		      printf("unknown suffix %d\n", instrtab[cnt].suffix);
Packit Service 97d2fb
		      abort ();
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  if (deferred_start != NULL)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      ADD_STRING (color_off);
Packit Service 97d2fb
		      non_printing += strlen (color_off);
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  string_end_idx = bufcnt;
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
Packit Service 97d2fb
		case 'o':
Packit Service 97d2fb
		  if (prec == 1 && instrtab[cnt].fct1 != 0)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      /* First parameter.  */
Packit Service 97d2fb
		      if (deferred_start != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_NSTRING (deferred_start, deferred_len);
Packit Service 97d2fb
			  non_printing += deferred_len;
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      if (instrtab[cnt].str1 != 0)
Packit Service 97d2fb
			ADD_STRING (op1_str
Packit Service 97d2fb
				    + op1_str_idx[instrtab[cnt].str1 - 1]);
Packit Service 97d2fb
Packit Service 97d2fb
		      output_data.opoff1 = (instrtab[cnt].off1_1
Packit Service 97d2fb
					    + OFF1_1_BIAS - opoff);
Packit Service 97d2fb
		      output_data.opoff2 = (instrtab[cnt].off1_2
Packit Service 97d2fb
					    + OFF1_2_BIAS - opoff);
Packit Service 97d2fb
		      output_data.opoff3 = (instrtab[cnt].off1_3
Packit Service 97d2fb
					    + OFF1_3_BIAS - opoff);
Packit Service 97d2fb
		      int r = op1_fct[instrtab[cnt].fct1] (&output_data);
Packit Service 97d2fb
		      if (r < 0)
Packit Service 97d2fb
			goto not;
Packit Service 97d2fb
		      if (r > 0)
Packit Service 97d2fb
			goto enomem;
Packit Service 97d2fb
Packit Service 97d2fb
		      if (deferred_start != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_STRING (color_off);
Packit Service 97d2fb
			  non_printing += strlen (color_off);
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      string_end_idx = bufcnt;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else if (prec == 2 && instrtab[cnt].fct2 != 0)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      /* Second parameter.  */
Packit Service 97d2fb
		      if (deferred_start != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_NSTRING (deferred_start, deferred_len);
Packit Service 97d2fb
			  non_printing += deferred_len;
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      if (instrtab[cnt].str2 != 0)
Packit Service 97d2fb
			ADD_STRING (op2_str
Packit Service 97d2fb
				    + op2_str_idx[instrtab[cnt].str2 - 1]);
Packit Service 97d2fb
Packit Service 97d2fb
		      output_data.opoff1 = (instrtab[cnt].off2_1
Packit Service 97d2fb
					    + OFF2_1_BIAS - opoff);
Packit Service 97d2fb
		      output_data.opoff2 = (instrtab[cnt].off2_2
Packit Service 97d2fb
					    + OFF2_2_BIAS - opoff);
Packit Service 97d2fb
		      output_data.opoff3 = (instrtab[cnt].off2_3
Packit Service 97d2fb
					    + OFF2_3_BIAS - opoff);
Packit Service 97d2fb
		      int r = op2_fct[instrtab[cnt].fct2] (&output_data);
Packit Service 97d2fb
		      if (r < 0)
Packit Service 97d2fb
			goto not;
Packit Service 97d2fb
		      if (r > 0)
Packit Service 97d2fb
			goto enomem;
Packit Service 97d2fb
Packit Service 97d2fb
		      if (deferred_start != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_STRING (color_off);
Packit Service 97d2fb
			  non_printing += strlen (color_off);
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      string_end_idx = bufcnt;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else if (prec == 3 && instrtab[cnt].fct3 != 0)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      /* Third parameter.  */
Packit Service 97d2fb
		      if (deferred_start != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_NSTRING (deferred_start, deferred_len);
Packit Service 97d2fb
			  non_printing += deferred_len;
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      if (instrtab[cnt].str3 != 0)
Packit Service 97d2fb
			ADD_STRING (op3_str
Packit Service 97d2fb
				    + op3_str_idx[instrtab[cnt].str3 - 1]);
Packit Service 97d2fb
Packit Service 97d2fb
		      output_data.opoff1 = (instrtab[cnt].off3_1
Packit Service 97d2fb
					    + OFF3_1_BIAS - opoff);
Packit Service 97d2fb
		      output_data.opoff2 = (instrtab[cnt].off3_2
Packit Service 97d2fb
					    + OFF3_2_BIAS - opoff);
Packit Service 97d2fb
#ifdef OFF3_3_BITS
Packit Service 97d2fb
		      output_data.opoff3 = (instrtab[cnt].off3_3
Packit Service 97d2fb
					    + OFF3_3_BIAS - opoff);
Packit Service 97d2fb
#else
Packit Service 97d2fb
		      output_data.opoff3 = 0;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
		      int r = op3_fct[instrtab[cnt].fct3] (&output_data);
Packit Service 97d2fb
		      if (r < 0)
Packit Service 97d2fb
			goto not;
Packit Service 97d2fb
		      if (r > 0)
Packit Service 97d2fb
			goto enomem;
Packit Service 97d2fb
Packit Service 97d2fb
		      if (deferred_start != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  ADD_STRING (color_off);
Packit Service 97d2fb
			  non_printing += strlen (color_off);
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      string_end_idx = bufcnt;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    start_idx = bufcnt = string_end_idx;
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
Packit Service 97d2fb
		case 'e':
Packit Service 97d2fb
		  string_end_idx = bufcnt;
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
Packit Service 97d2fb
		case 'a':
Packit Service 97d2fb
		  /* Pad to requested column.  */
Packit Service 97d2fb
		  while (bufcnt - non_printing < (size_t) width)
Packit Service 97d2fb
		    ADD_CHAR (' ');
Packit Service 97d2fb
		  width = 0;
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
Packit Service 97d2fb
		case 'l':
Packit Service 97d2fb
		  if (deferred_start != NULL)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      ADD_NSTRING (deferred_start, deferred_len);
Packit Service 97d2fb
		      non_printing += deferred_len;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  if (output_data.labelbuf != NULL
Packit Service 97d2fb
		      && output_data.labelbuf[0] != '\0')
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      ADD_STRING (output_data.labelbuf);
Packit Service 97d2fb
		      output_data.labelbuf[0] = '\0';
Packit Service 97d2fb
		      string_end_idx = bufcnt;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else if (output_data.symaddr_use != addr_none)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      GElf_Addr symaddr = output_data.symaddr;
Packit Service 97d2fb
		      if (output_data.symaddr_use >= addr_rel_symbolic)
Packit Service 97d2fb
			symaddr += addr + param_start - begin;
Packit Service 97d2fb
Packit Service 97d2fb
		      // XXX Lookup symbol based on symaddr
Packit Service 97d2fb
		      const char *symstr = NULL;
Packit Service 97d2fb
		      if (symcb != NULL
Packit Service 97d2fb
			  && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
Packit Service 97d2fb
				    &output_data.labelbuf,
Packit Service 97d2fb
				    &output_data.labelbufsize, symcbarg) == 0)
Packit Service 97d2fb
			symstr = output_data.labelbuf;
Packit Service 97d2fb
Packit Service 97d2fb
		      size_t bufavail = bufsize - bufcnt;
Packit Service 97d2fb
		      int r = 0;
Packit Service 97d2fb
		      if (symstr != NULL)
Packit Service 97d2fb
			r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
Packit Service 97d2fb
				      symstr);
Packit Service 97d2fb
		      else if (output_data.symaddr_use == addr_abs_always
Packit Service 97d2fb
			       || output_data.symaddr_use == addr_rel_always)
Packit Service 97d2fb
			r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
Packit Service 97d2fb
				      (uint64_t) symaddr);
Packit Service 97d2fb
Packit Service 97d2fb
		      assert (r >= 0);
Packit Service 97d2fb
		      if ((size_t) r >= bufavail)
Packit Service 97d2fb
			goto enomem;
Packit Service 97d2fb
		      bufcnt += r;
Packit Service 97d2fb
		      string_end_idx = bufcnt;
Packit Service 97d2fb
Packit Service 97d2fb
		      output_data.symaddr_use = addr_none;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  if (deferred_start != NULL)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      ADD_STRING (color_off);
Packit Service 97d2fb
		      non_printing += strlen (color_off);
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
Packit Service 97d2fb
		default:
Packit Service 97d2fb
		  abort ();
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      deferred_start = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Pad according to the specified width.  */
Packit Service 97d2fb
	      while (bufcnt + prefix_size - non_printing < start_idx + width)
Packit Service 97d2fb
		ADD_CHAR (' ');
Packit Service 97d2fb
	      prefix_size = 0;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if ((prefixes & SEGMENT_PREFIXES) != 0)
Packit Service 97d2fb
	    goto print_prefix;
Packit Service 97d2fb
Packit Service 97d2fb
	  assert (string_end_idx != ~0ul);
Packit Service 97d2fb
	  bufcnt = string_end_idx;
Packit Service 97d2fb
Packit Service 97d2fb
	  addr += param_start - begin;
Packit Service 97d2fb
	  data = param_start;
Packit Service 97d2fb
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Invalid (or at least unhandled) opcode.  */
Packit Service 97d2fb
    invalid_op:
Packit Service 97d2fb
      if (prefixes != 0)
Packit Service 97d2fb
	goto print_prefix;
Packit Service 97d2fb
      /* Make sure we get past the unrecognized opcode if we haven't yet.  */
Packit Service 97d2fb
      if (*startp == data)
Packit Service 97d2fb
	++data;
Packit Service 97d2fb
      ADD_STRING ("(bad)");
Packit Service 97d2fb
      addr += data - begin;
Packit Service 97d2fb
Packit Service 97d2fb
    out:
Packit Service 97d2fb
      if (bufcnt == bufsize)
Packit Service 97d2fb
	goto enomem;
Packit Service 97d2fb
      buf[bufcnt] = '\0';
Packit Service 97d2fb
Packit Service 97d2fb
      *startp = data;
Packit Service 97d2fb
      retval = outcb (buf, bufcnt, outcbarg);
Packit Service 97d2fb
      if (retval != 0)
Packit Service 97d2fb
	goto do_ret;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
 do_ret:
Packit Service 97d2fb
  free (output_data.labelbuf);
Packit Service 97d2fb
  if (buf != initbuf)
Packit Service 97d2fb
    free (buf);
Packit Service 97d2fb
Packit Service 97d2fb
  return retval;
Packit Service 97d2fb
}