Line data Source code
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
315 2 : 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 2 : const char *save_fmt = fmt;
321 :
322 : #define BUFSIZE 512
323 : char initbuf[BUFSIZE];
324 : int prefixes;
325 : size_t bufcnt;
326 2 : size_t bufsize = BUFSIZE;
327 2 : char *buf = initbuf;
328 : const uint8_t *param_start;
329 :
330 2 : 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 2 : int retval = 0;
341 : while (1)
342 : {
343 18946 : prefixes = 0;
344 :
345 18946 : const uint8_t *data = *startp;
346 18946 : const uint8_t *begin = data;
347 :
348 : /* Recognize all prefixes. */
349 18946 : int last_prefix_bit = 0;
350 43124 : while (data < end)
351 : {
352 : unsigned int i;
353 242722 : for (i = idx_cs; i < nknown_prefixes; ++i)
354 247954 : if (known_prefixes[i] == *data)
355 : break;
356 24176 : if (i == nknown_prefixes)
357 : break;
358 :
359 5232 : prefixes |= last_prefix_bit = 1 << i;
360 :
361 5232 : ++data;
362 : }
363 :
364 : #ifdef X86_64
365 11423 : if (data < end && (*data & 0xf0) == 0x40)
366 3921 : prefixes |= ((*data++) & 0xf) | has_rex;
367 : #endif
368 :
369 18946 : bufcnt = 0;
370 18946 : size_t cnt = 0;
371 :
372 18946 : const uint8_t *curr = match_data;
373 18946 : const uint8_t *const match_end = match_data + sizeof (match_data);
374 :
375 18946 : assert (data <= end);
376 18946 : if (data == end)
377 : {
378 2 : if (prefixes != 0)
379 : goto print_prefix;
380 :
381 : retval = -1;
382 : goto do_ret;
383 : }
384 :
385 : next_match:
386 5331965 : while (curr < match_end)
387 : {
388 5331965 : uint_fast8_t len = *curr++;
389 5331965 : uint_fast8_t clen = len >> 4;
390 5331965 : len &= 0xf;
391 5331965 : const uint8_t *next_curr = curr + clen + (len - clen) * 2;
392 :
393 5331965 : assert (len > 0);
394 5331965 : assert (curr + clen + 2 * (len - clen) <= match_end);
395 :
396 5331965 : const uint8_t *codep = data;
397 5331965 : int correct_prefix = 0;
398 5331965 : int opoff = 0;
399 :
400 5331965 : 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 342612 : --len;
405 342612 : --clen;
406 342612 : opoff = 8;
407 :
408 342612 : ++curr;
409 :
410 342612 : assert (last_prefix_bit != 0);
411 : correct_prefix = last_prefix_bit;
412 : }
413 :
414 5331965 : size_t avail = len;
415 12358266 : while (clen > 0)
416 : {
417 5742833 : if (*codep++ != *curr++)
418 : goto not;
419 1694336 : --avail;
420 1694336 : --clen;
421 1694336 : if (codep == end && avail > 0)
422 : goto do_ret;
423 : }
424 :
425 1315233 : while (avail > 0)
426 : {
427 1296287 : uint_fast8_t masked = *codep++ & *curr++;
428 1296287 : if (masked != *curr++)
429 : {
430 : not:
431 5313021 : curr = next_curr;
432 5313021 : ++cnt;
433 5313021 : bufcnt = 0;
434 5313021 : goto next_match;
435 : }
436 :
437 31765 : --avail;
438 31765 : if (codep == end && avail > 0)
439 : goto do_ret;
440 : }
441 :
442 18946 : 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 18946 : assert (correct_prefix == 0
449 : || (prefixes & correct_prefix) != 0);
450 18946 : prefixes ^= correct_prefix;
451 :
452 : if (0)
453 : {
454 : /* Resize the buffer. */
455 : char *oldbuf;
456 : enomem:
457 0 : oldbuf = buf;
458 0 : if (buf == initbuf)
459 0 : buf = malloc (2 * bufsize);
460 : else
461 0 : buf = realloc (buf, 2 * bufsize);
462 0 : if (buf == NULL)
463 : {
464 : buf = oldbuf;
465 : retval = ENOMEM;
466 : goto do_ret;
467 : }
468 0 : bufsize *= 2;
469 :
470 0 : output_data.bufp = buf;
471 0 : output_data.bufsize = bufsize;
472 0 : bufcnt = 0;
473 :
474 0 : if (data == end)
475 : {
476 0 : 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 0 : asm (""
483 : : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
484 : "=mr" (next_curr), "=mr" (len));
485 : }
486 :
487 18946 : size_t prefix_size = 0;
488 :
489 : // XXXonly print as prefix if valid?
490 18946 : if ((prefixes & has_lock) != 0)
491 : {
492 0 : ADD_STRING ("lock ");
493 0 : prefix_size += 5;
494 : }
495 :
496 18946 : if (instrtab[cnt].rep)
497 : {
498 36 : if ((prefixes & has_rep) != 0)
499 : {
500 0 : ADD_STRING ("rep ");
501 0 : prefix_size += 4;
502 : }
503 : }
504 18910 : else if (instrtab[cnt].repe
505 18 : && (prefixes & (has_rep | has_repne)) != 0)
506 : {
507 0 : if ((prefixes & has_repne) != 0)
508 : {
509 0 : ADD_STRING ("repne ");
510 0 : prefix_size += 6;
511 : }
512 0 : else if ((prefixes & has_rep) != 0)
513 : {
514 0 : ADD_STRING ("repe ");
515 0 : prefix_size += 5;
516 : }
517 : }
518 18910 : else if ((prefixes & (has_rep | has_repne)) != 0)
519 : {
520 : uint_fast8_t byte;
521 : print_prefix:
522 9 : bufcnt = 0;
523 9 : byte = *begin;
524 : /* This is a prefix byte. Print it. */
525 9 : switch (byte)
526 : {
527 : case prefix_rep:
528 0 : ADD_STRING ("rep");
529 0 : break;
530 : case prefix_repne:
531 0 : ADD_STRING ("repne");
532 0 : break;
533 : case prefix_cs:
534 1 : ADD_STRING ("cs");
535 1 : break;
536 : case prefix_ds:
537 2 : ADD_STRING ("ds");
538 2 : break;
539 : case prefix_es:
540 1 : ADD_STRING ("es");
541 1 : break;
542 : case prefix_fs:
543 2 : ADD_STRING ("fs");
544 2 : break;
545 : case prefix_gs:
546 2 : ADD_STRING ("gs");
547 2 : break;
548 : case prefix_ss:
549 1 : ADD_STRING ("ss");
550 1 : break;
551 : case prefix_data16:
552 0 : ADD_STRING ("data16");
553 0 : break;
554 : case prefix_addr16:
555 0 : ADD_STRING ("addr16");
556 0 : break;
557 : case prefix_lock:
558 0 : ADD_STRING ("lock");
559 0 : break;
560 : #ifdef X86_64
561 : case 0x40 ... 0x4f:
562 0 : ADD_STRING ("rex");
563 0 : if (byte != 0x40)
564 : {
565 0 : ADD_CHAR ('.');
566 0 : if (byte & 0x8)
567 0 : ADD_CHAR ('w');
568 0 : if (byte & 0x4)
569 0 : ADD_CHAR ('r');
570 0 : if (byte & 0x3)
571 0 : ADD_CHAR ('x');
572 0 : if (byte & 0x1)
573 0 : ADD_CHAR ('b');
574 : }
575 : break;
576 : #endif
577 : default:
578 : /* Cannot happen. */
579 0 : puts ("unknown prefix");
580 0 : abort ();
581 : }
582 9 : data = begin + 1;
583 9 : ++addr;
584 :
585 9 : goto out;
586 : }
587 :
588 : /* We have a match. First determine how many bytes are
589 : needed for the adressing mode. */
590 18946 : param_start = codep;
591 18946 : if (instrtab[cnt].modrm)
592 : {
593 16758 : uint_fast8_t modrm = codep[-1];
594 :
595 : #ifndef X86_64
596 6426 : if (likely ((prefixes & has_addr16) != 0))
597 : {
598 : /* Account for displacement. */
599 40 : if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
600 17 : param_start += 2;
601 23 : else if ((modrm & 0xc0) == 0x40)
602 16 : param_start += 1;
603 : }
604 : else
605 : #endif
606 : {
607 : /* Account for SIB. */
608 16718 : if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
609 6136 : param_start += 1;
610 :
611 : /* Account for displacement. */
612 16718 : if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
613 12994 : || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
614 4066 : param_start += 4;
615 12652 : else if ((modrm & 0xc0) == 0x40)
616 3581 : param_start += 1;
617 : }
618 :
619 16758 : if (unlikely (param_start > end))
620 : goto not;
621 : }
622 :
623 18946 : output_data.addr = addr + (data - begin);
624 18946 : output_data.data = data;
625 :
626 18946 : unsigned long string_end_idx = 0;
627 18946 : fmt = save_fmt;
628 18946 : const char *deferred_start = NULL;
629 18946 : size_t deferred_len = 0;
630 : // XXX Can we get this from color.c?
631 : static const char color_off[] = "\e[0m";
632 227332 : while (*fmt != '\0')
633 : {
634 189442 : if (*fmt != '%')
635 : {
636 75776 : char ch = *fmt++;
637 75776 : if (ch == '\\')
638 : {
639 0 : switch ((ch = *fmt++))
640 : {
641 : case '0' ... '7':
642 : {
643 0 : int val = ch - '0';
644 0 : ch = *fmt;
645 0 : if (ch >= '0' && ch <= '7')
646 : {
647 0 : val *= 8;
648 0 : val += ch - '0';
649 0 : ch = *++fmt;
650 0 : if (ch >= '0' && ch <= '7' && val < 32)
651 : {
652 0 : val *= 8;
653 0 : val += ch - '0';
654 0 : ++fmt;
655 : }
656 : }
657 0 : ch = val;
658 : }
659 0 : break;
660 :
661 : case 'n':
662 : ch = '\n';
663 : break;
664 :
665 : case 't':
666 0 : ch = '\t';
667 0 : break;
668 :
669 : default:
670 : retval = EINVAL;
671 : goto do_ret;
672 : }
673 : }
674 75776 : else if (ch == '\e' && *fmt == '[')
675 : {
676 : deferred_start = fmt - 1;
677 : do
678 0 : ++fmt;
679 0 : while (*fmt != 'm' && *fmt != '\0');
680 :
681 0 : if (*fmt == 'm')
682 : {
683 0 : deferred_len = ++fmt - deferred_start;
684 0 : continue;
685 : }
686 :
687 : fmt = deferred_start + 1;
688 : deferred_start = NULL;
689 : }
690 75776 : ADD_CHAR (ch);
691 75776 : continue;
692 : }
693 113666 : ++fmt;
694 :
695 113666 : int width = 0;
696 284166 : while (isdigit (*fmt))
697 56834 : width = width * 10 + (*fmt++ - '0');
698 :
699 113666 : int prec = 0;
700 113666 : if (*fmt == '.')
701 113664 : while (isdigit (*++fmt))
702 56832 : prec = prec * 10 + (*fmt - '0');
703 :
704 113666 : size_t start_idx = bufcnt;
705 113666 : size_t non_printing = 0;
706 113666 : switch (*fmt++)
707 : {
708 : char mnebuf[16];
709 : const char *str;
710 :
711 : case 'm':
712 : /* Mnemonic. */
713 :
714 18946 : if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
715 : {
716 217 : switch (*data)
717 : {
718 : #ifdef X86_64
719 : case 0x90:
720 3 : if (prefixes & has_rex_b)
721 : goto not;
722 : str = "nop";
723 : break;
724 : #endif
725 :
726 : case 0x98:
727 : #ifdef X86_64
728 4 : if (prefixes == (has_rex_w | has_rex))
729 : {
730 : str = "cltq";
731 : break;
732 : }
733 : #endif
734 5 : if (prefixes & ~has_data16)
735 : goto print_prefix;
736 5 : str = prefixes & has_data16 ? "cbtw" : "cwtl";
737 : break;
738 :
739 : case 0x99:
740 : #ifdef X86_64
741 4 : if (prefixes == (has_rex_w | has_rex))
742 : {
743 : str = "cqto";
744 : break;
745 : }
746 : #endif
747 5 : if (prefixes & ~has_data16)
748 : goto print_prefix;
749 5 : str = prefixes & has_data16 ? "cwtd" : "cltd";
750 : break;
751 :
752 : case 0xe3:
753 8 : if (prefixes & ~has_addr16)
754 : goto print_prefix;
755 : #ifdef X86_64
756 4 : str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
757 : #else
758 4 : str = prefixes & has_addr16 ? "jcxz" : "jecxz";
759 : #endif
760 : break;
761 :
762 : case 0x0f:
763 194 : if (data[1] == 0x0f)
764 : {
765 : /* AMD 3DNOW. We need one more byte. */
766 100 : if (param_start >= end)
767 : goto not;
768 200 : if (*param_start < AMD3DNOW_LOW_IDX
769 100 : || *param_start > AMD3DNOW_HIGH_IDX)
770 : goto not;
771 100 : unsigned int idx
772 100 : = amd3dnow[AMD3DNOW_IDX (*param_start)];
773 100 : if (idx == 0)
774 : goto not;
775 100 : str = amd3dnowstr + idx - 1;
776 : /* Eat the immediate byte indicating the
777 : operation. */
778 100 : ++param_start;
779 100 : break;
780 : }
781 : #ifdef X86_64
782 50 : if (data[1] == 0xc7)
783 : {
784 6 : str = ((prefixes & has_rex_w)
785 6 : ? "cmpxchg16b" : "cmpxchg8b");
786 : break;
787 : }
788 : #endif
789 88 : if (data[1] == 0xc2)
790 : {
791 88 : if (param_start >= end)
792 : goto not;
793 88 : 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 88 : char *cp = stpcpy (mnebuf, cmpops[*param_start]);
807 88 : if (correct_prefix & (has_rep | has_repne))
808 44 : *cp++ = 's';
809 : else
810 44 : *cp++ = 'p';
811 88 : if (correct_prefix & (has_data16 | has_repne))
812 44 : *cp++ = 'd';
813 : else
814 44 : *cp++ = 's';
815 88 : *cp = '\0';
816 88 : str = mnebuf;
817 : /* Eat the immediate byte indicating the
818 : operation. */
819 88 : ++param_start;
820 88 : break;
821 : }
822 : /* Fallthrough */
823 : default:
824 0 : assert (! "INVALID not handled");
825 : }
826 : }
827 : else
828 18729 : str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
829 :
830 18944 : if (deferred_start != NULL)
831 : {
832 0 : ADD_NSTRING (deferred_start, deferred_len);
833 0 : non_printing += deferred_len;
834 : }
835 :
836 18944 : ADD_STRING (str);
837 :
838 18944 : switch (instrtab[cnt].suffix)
839 : {
840 : case suffix_none:
841 : break;
842 :
843 : case suffix_w:
844 1017 : if ((codep[-1] & 0xc0) != 0xc0)
845 : {
846 : char ch;
847 :
848 783 : if (data[0] & 1)
849 : {
850 489 : if (prefixes & has_data16)
851 : ch = 'w';
852 : #ifdef X86_64
853 215 : else if (prefixes & has_rex_w)
854 : ch = 'q';
855 : #endif
856 : else
857 419 : ch = 'l';
858 : }
859 : else
860 : ch = 'b';
861 :
862 783 : ADD_CHAR (ch);
863 : }
864 : break;
865 :
866 : case suffix_w0:
867 6 : if ((codep[-1] & 0xc0) != 0xc0)
868 6 : ADD_CHAR ('l');
869 : break;
870 :
871 : case suffix_w1:
872 108 : if ((data[0] & 0x4) == 0)
873 54 : ADD_CHAR ('l');
874 : break;
875 :
876 : case suffix_W:
877 84 : if (prefixes & has_data16)
878 : {
879 4 : ADD_CHAR ('w');
880 4 : prefixes &= ~has_data16;
881 : }
882 : #ifdef X86_64
883 : else
884 44 : ADD_CHAR ('q');
885 : #endif
886 : break;
887 :
888 : case suffix_W1:
889 4 : if (prefixes & has_data16)
890 : {
891 2 : ADD_CHAR ('w');
892 2 : prefixes &= ~has_data16;
893 : }
894 : #ifdef X86_64
895 1 : else if (prefixes & has_rex_w)
896 0 : 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 288 : ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
907 288 : break;
908 :
909 : case suffix_D:
910 132 : if ((codep[-1] & 0xc0) != 0xc0)
911 132 : ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
912 : break;
913 :
914 : default:
915 0 : printf("unknown suffix %d\n", instrtab[cnt].suffix);
916 0 : abort ();
917 : }
918 :
919 18944 : if (deferred_start != NULL)
920 : {
921 0 : ADD_STRING (color_off);
922 0 : non_printing += strlen (color_off);
923 : }
924 :
925 18944 : string_end_idx = bufcnt;
926 132608 : break;
927 :
928 : case 'o':
929 56832 : if (prec == 1 && instrtab[cnt].fct1 != 0)
930 18759 : {
931 : /* First parameter. */
932 18759 : if (deferred_start != NULL)
933 : {
934 0 : ADD_NSTRING (deferred_start, deferred_len);
935 0 : non_printing += deferred_len;
936 : }
937 :
938 18759 : if (instrtab[cnt].str1 != 0)
939 446 : ADD_STRING (op1_str
940 : + op1_str_idx[instrtab[cnt].str1 - 1]);
941 :
942 37518 : output_data.opoff1 = (instrtab[cnt].off1_1
943 18759 : + OFF1_1_BIAS - opoff);
944 37518 : output_data.opoff2 = (instrtab[cnt].off1_2
945 18759 : + OFF1_2_BIAS - opoff);
946 37518 : output_data.opoff3 = (instrtab[cnt].off1_3
947 18759 : + OFF1_3_BIAS - opoff);
948 18759 : int r = op1_fct[instrtab[cnt].fct1] (&output_data);
949 18759 : if (r < 0)
950 : goto not;
951 18759 : if (r > 0)
952 : goto enomem;
953 :
954 18759 : if (deferred_start != NULL)
955 : {
956 0 : ADD_STRING (color_off);
957 0 : non_printing += strlen (color_off);
958 : }
959 :
960 18759 : string_end_idx = bufcnt;
961 : }
962 38073 : else if (prec == 2 && instrtab[cnt].fct2 != 0)
963 17326 : {
964 : /* Second parameter. */
965 17326 : if (deferred_start != NULL)
966 : {
967 0 : ADD_NSTRING (deferred_start, deferred_len);
968 0 : non_printing += deferred_len;
969 : }
970 :
971 17326 : if (instrtab[cnt].str2 != 0)
972 292 : ADD_STRING (op2_str
973 : + op2_str_idx[instrtab[cnt].str2 - 1]);
974 :
975 34652 : output_data.opoff1 = (instrtab[cnt].off2_1
976 17326 : + OFF2_1_BIAS - opoff);
977 34652 : output_data.opoff2 = (instrtab[cnt].off2_2
978 17326 : + OFF2_2_BIAS - opoff);
979 34652 : output_data.opoff3 = (instrtab[cnt].off2_3
980 17326 : + OFF2_3_BIAS - opoff);
981 17326 : int r = op2_fct[instrtab[cnt].fct2] (&output_data);
982 17326 : if (r < 0)
983 : goto not;
984 17326 : if (r > 0)
985 : goto enomem;
986 :
987 17326 : if (deferred_start != NULL)
988 : {
989 0 : ADD_STRING (color_off);
990 0 : non_printing += strlen (color_off);
991 : }
992 :
993 17326 : string_end_idx = bufcnt;
994 : }
995 20747 : else if (prec == 3 && instrtab[cnt].fct3 != 0)
996 812 : {
997 : /* Third parameter. */
998 812 : if (deferred_start != NULL)
999 : {
1000 0 : ADD_NSTRING (deferred_start, deferred_len);
1001 0 : non_printing += deferred_len;
1002 : }
1003 :
1004 812 : if (instrtab[cnt].str3 != 0)
1005 2 : ADD_STRING (op3_str
1006 : + op3_str_idx[instrtab[cnt].str3 - 1]);
1007 :
1008 1624 : output_data.opoff1 = (instrtab[cnt].off3_1
1009 812 : + OFF3_1_BIAS - opoff);
1010 1624 : output_data.opoff2 = (instrtab[cnt].off3_2
1011 812 : + 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 812 : output_data.opoff3 = 0;
1017 : #endif
1018 812 : int r = op3_fct[instrtab[cnt].fct3] (&output_data);
1019 812 : if (r < 0)
1020 : goto not;
1021 812 : if (r > 0)
1022 : goto enomem;
1023 :
1024 812 : if (deferred_start != NULL)
1025 : {
1026 0 : ADD_STRING (color_off);
1027 0 : non_printing += strlen (color_off);
1028 : }
1029 :
1030 812 : string_end_idx = bufcnt;
1031 : }
1032 : else
1033 19935 : 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 204106 : while (bufcnt - non_printing < (size_t) width)
1043 185162 : ADD_CHAR (' ');
1044 : width = 0;
1045 : break;
1046 :
1047 : case 'l':
1048 18944 : if (deferred_start != NULL)
1049 : {
1050 0 : ADD_NSTRING (deferred_start, deferred_len);
1051 0 : non_printing += deferred_len;
1052 : }
1053 :
1054 18944 : if (output_data.labelbuf != NULL
1055 0 : && output_data.labelbuf[0] != '\0')
1056 : {
1057 0 : ADD_STRING (output_data.labelbuf);
1058 0 : output_data.labelbuf[0] = '\0';
1059 0 : string_end_idx = bufcnt;
1060 : }
1061 18944 : else if (output_data.symaddr_use != addr_none)
1062 : {
1063 111 : GElf_Addr symaddr = output_data.symaddr;
1064 111 : if (output_data.symaddr_use >= addr_rel_symbolic)
1065 111 : symaddr += addr + param_start - begin;
1066 :
1067 : // XXX Lookup symbol based on symaddr
1068 111 : const char *symstr = NULL;
1069 111 : if (symcb != NULL
1070 111 : && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
1071 : &output_data.labelbuf,
1072 : &output_data.labelbufsize, symcbarg) == 0)
1073 0 : symstr = output_data.labelbuf;
1074 :
1075 111 : size_t bufavail = bufsize - bufcnt;
1076 111 : int r = 0;
1077 111 : if (symstr != NULL)
1078 0 : r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
1079 : symstr);
1080 222 : else if (output_data.symaddr_use == addr_abs_always
1081 111 : || output_data.symaddr_use == addr_rel_always)
1082 111 : r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
1083 : (uint64_t) symaddr);
1084 :
1085 111 : assert (r >= 0);
1086 111 : if ((size_t) r >= bufavail)
1087 : goto enomem;
1088 111 : bufcnt += r;
1089 111 : string_end_idx = bufcnt;
1090 :
1091 111 : output_data.symaddr_use = addr_none;
1092 : }
1093 18944 : if (deferred_start != NULL)
1094 : {
1095 0 : ADD_STRING (color_off);
1096 0 : non_printing += strlen (color_off);
1097 : }
1098 : break;
1099 :
1100 : default:
1101 0 : abort ();
1102 : }
1103 :
1104 113664 : deferred_start = NULL;
1105 :
1106 : /* Pad according to the specified width. */
1107 298650 : while (bufcnt + prefix_size - non_printing < start_idx + width)
1108 71322 : ADD_CHAR (' ');
1109 : prefix_size = 0;
1110 : }
1111 :
1112 18944 : if ((prefixes & SEGMENT_PREFIXES) != 0)
1113 : goto print_prefix;
1114 :
1115 18935 : assert (string_end_idx != ~0ul);
1116 18935 : bufcnt = string_end_idx;
1117 :
1118 18935 : addr += param_start - begin;
1119 18935 : data = param_start;
1120 :
1121 18935 : goto out;
1122 : }
1123 :
1124 : /* Invalid (or at least unhandled) opcode. */
1125 0 : if (prefixes != 0)
1126 : goto print_prefix;
1127 0 : assert (*startp == data);
1128 0 : ++data;
1129 0 : ADD_STRING ("(bad)");
1130 0 : addr += data - begin;
1131 :
1132 : out:
1133 18944 : if (bufcnt == bufsize)
1134 : goto enomem;
1135 18944 : buf[bufcnt] = '\0';
1136 :
1137 18944 : *startp = data;
1138 18944 : retval = outcb (buf, bufcnt, outcbarg);
1139 18944 : if (retval != 0)
1140 : goto do_ret;
1141 : }
1142 :
1143 : do_ret:
1144 2 : free (output_data.labelbuf);
1145 2 : if (buf != initbuf)
1146 0 : free (buf);
1147 :
1148 2 : return retval;
1149 : }
|