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