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