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