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 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 FALLTHROUGH;
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