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