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