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