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