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