1 /*- 2 * Copyright (c) 2016 Cavium 3 * All rights reserved. 4 * 5 * This software was developed by Semihalf. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 35 #include <machine/armreg.h> 36 #include <machine/disassem.h> 37 38 #include <ddb/ddb.h> 39 40 #define ARM64_MAX_TOKEN_LEN 8 41 #define ARM64_MAX_TOKEN_CNT 10 42 43 #define ARM_INSN_SIZE_OFFSET 30 44 #define ARM_INSN_SIZE_MASK 0x3 45 46 /* Special options for instruction printing */ 47 #define OP_SIGN_EXT (1UL << 0) /* Sign-extend immediate value */ 48 #define OP_LITERAL (1UL << 1) /* Use literal (memory offset) */ 49 #define OP_MULT_4 (1UL << 2) /* Multiply immediate by 4 */ 50 #define OP_SF32 (1UL << 3) /* Force 32-bit access */ 51 #define OP_SF_INV (1UL << 6) /* SF is inverted (1 means 32 bit access) */ 52 #define OP_RD_SP (1UL << 7) /* Use sp for RD otherwise xzr */ 53 #define OP_RT_SP (1UL << 8) /* Use sp for RT otherwise xzr */ 54 #define OP_RN_SP (1UL << 9) /* Use sp for RN otherwise xzr */ 55 #define OP_RM_SP (1UL << 10) /* Use sp for RM otherwise xzr */ 56 57 static const char *w_reg[] = { 58 "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", 59 "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", 60 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", 61 "w24", "w25", "w26", "w27", "w28", "w29", "w30" 62 }; 63 64 static const char *x_reg[] = { 65 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 66 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 67 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 68 "x24", "x25", "x26", "x27", "x28", "x29", "LR" 69 }; 70 71 static const char *shift_2[] = { 72 "LSL", "LSR", "ASR", "RSV" 73 }; 74 75 /* 76 * Structure representing single token (operand) inside instruction. 77 * name - name of operand 78 * pos - position within the instruction (in bits) 79 * len - operand length (in bits) 80 */ 81 struct arm64_insn_token { 82 char name[ARM64_MAX_TOKEN_LEN]; 83 int pos; 84 int len; 85 }; 86 87 /* 88 * Define generic types for instruction printing. 89 */ 90 enum arm64_format_type { 91 /* 92 * OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #imm} SF32/64 93 * OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64 94 */ 95 TYPE_01, 96 97 /* 98 * OP <RT>, [<RN>, #<imm>]{!} SF32/64 99 * OP <RT>, [<RN>], #<imm>{!} SF32/64 100 * OP <RT>, <RN>, <RM> {, EXTEND AMOUNT } 101 */ 102 TYPE_02, 103 104 /* OP <RT>, #imm SF32/64 */ 105 TYPE_03, 106 }; 107 108 /* 109 * Structure representing single parsed instruction format. 110 * name - opcode name 111 * format - opcode format in a human-readable way 112 * type - syntax type for printing 113 * special_ops - special options passed to a printer (if any) 114 * mask - bitmask for instruction matching 115 * pattern - pattern to look for 116 * tokens - array of tokens (operands) inside instruction 117 */ 118 struct arm64_insn { 119 char *name; 120 char *format; 121 enum arm64_format_type type; 122 uint64_t special_ops; 123 uint32_t mask; 124 uint32_t pattern; 125 struct arm64_insn_token tokens[ARM64_MAX_TOKEN_CNT]; 126 }; 127 128 /* 129 * Specify instruction opcode format in a human-readable way. Use notation 130 * obtained from ARM Architecture Reference Manual for ARMv8-A. 131 * 132 * Format string description: 133 * Each group must be separated by "|". Group made of 0/1 is used to 134 * generate mask and pattern for instruction matching. Groups containing 135 * an operand token (in format NAME(length_bits)) are used to retrieve any 136 * operand data from the instruction. Names here must be meaningful 137 * and match the one described in the Manual. 138 * 139 * Token description: 140 * SF - "0" represents 32-bit access, "1" represents 64-bit access 141 * SHIFT - type of shift (instruction dependent) 142 * IMM - immediate value 143 * Rx - register number 144 * OPTION - command specific options 145 * SCALE - scaling of immediate value 146 */ 147 static struct arm64_insn arm64_i[] = { 148 { "add", "SF(1)|0001011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)", 149 TYPE_01, 0 }, /* add shifted register */ 150 { "mov", "SF(1)|001000100000000000000|RN(5)|RD(5)", 151 TYPE_01, OP_RD_SP | OP_RN_SP }, /* mov (to/from sp) */ 152 { "add", "SF(1)|0010001|SHIFT(2)|IMM(12)|RN(5)|RD(5)", 153 TYPE_01, OP_RD_SP | OP_RN_SP }, /* add immediate */ 154 { "ldr", "1|SF(1)|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", 155 TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* ldr immediate post/pre index */ 156 { "ldr", "1|SF(1)|11100101|IMM(12)|RN(5)|RT(5)", 157 TYPE_02, OP_RN_SP }, /* ldr immediate unsigned */ 158 { "ldr", "1|SF(1)|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 159 TYPE_02, OP_RN_SP }, /* ldr register */ 160 { "ldr", "0|SF(1)|011000|IMM(19)|RT(5)", 161 TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */ 162 { "ldrb", "00|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", 163 TYPE_02, OP_SIGN_EXT | OP_SF32 | OP_RN_SP }, 164 /* ldrb immediate post/pre index */ 165 { "ldrb", "00|11100101|IMM(12)|RN(5)|RT(5)", 166 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrb immediate unsigned */ 167 { "ldrb", "00|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 168 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrb register */ 169 { "ldrh", "01|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", TYPE_02, 170 OP_SIGN_EXT | OP_SF32 | OP_RN_SP }, /* ldrh immediate post/pre index */ 171 { "ldrh", "01|11100101|IMM(12)|RN(5)|RT(5)", 172 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrh immediate unsigned */ 173 { "ldrh", "01|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 174 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrh register */ 175 { "ldrsb", "001110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)", 176 TYPE_02, OP_SIGN_EXT | OP_SF_INV | OP_RN_SP }, 177 /* ldrsb immediate post/pre index */ 178 { "ldrsb", "001110011|SF(1)|IMM(12)|RN(5)|RT(5)",\ 179 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsb immediate unsigned */ 180 { "ldrsb", "001110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 181 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsb register */ 182 { "ldrsh", "011110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)", 183 TYPE_02, OP_SIGN_EXT | OP_SF_INV | OP_RN_SP }, 184 /* ldrsh immediate post/pre index */ 185 { "ldrsh", "011110011|SF(1)|IMM(12)|RN(5)|RT(5)", 186 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsh immediate unsigned */ 187 { "ldrsh", "011110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 188 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsh register */ 189 { "ldrsw", "10111000100|IMM(9)|OPTION(2)|RN(5)|RT(5)", 190 TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* ldrsw immediate post/pre index */ 191 { "ldrsw", "1011100110|IMM(12)|RN(5)|RT(5)", 192 TYPE_02, OP_RN_SP }, /* ldrsw immediate unsigned */ 193 { "ldrsw", "10111000101|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 194 TYPE_02, OP_RN_SP }, /* ldrsw register */ 195 { "ldrsw", "10011000|IMM(19)|RT(5)", 196 TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldrsw literal */ 197 { "str", "1|SF(1)|111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)", 198 TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* str immediate post/pre index */ 199 { "str", "1|SF(1)|11100100|IMM(12)|RN(5)|RT(5)", 200 TYPE_02, OP_RN_SP }, /* str immediate unsigned */ 201 { "str", "1|SF(1)|111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 202 TYPE_02, OP_RN_SP }, /* str register */ 203 { "strb", "00111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)", 204 TYPE_02, OP_SIGN_EXT | OP_SF32 | OP_RN_SP }, 205 /* strb immediate post/pre index */ 206 { "strb", "0011100100|IMM(12)|RN(5)|RT(5)", 207 TYPE_02, OP_SF32 | OP_RN_SP }, /* strb immediate unsigned */ 208 { "strb", "00111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 209 TYPE_02, OP_SF32 | OP_RN_SP }, /* strb register */ 210 { "strh", "01111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)", 211 TYPE_02, OP_SF32 | OP_SIGN_EXT | OP_RN_SP }, 212 /* strh immediate post/pre index */ 213 { "strh", "0111100100|IMM(12)|RN(5)|RT(5)", 214 TYPE_02, OP_SF32 | OP_RN_SP }, 215 /* strh immediate unsigned */ 216 { "strh", "01111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)", 217 TYPE_02, OP_SF32 | OP_RN_SP }, 218 /* strh register */ 219 { NULL, NULL } 220 }; 221 222 static void 223 arm64_disasm_generate_masks(struct arm64_insn *tab) 224 { 225 uint32_t mask, val; 226 int a, i; 227 int len, ret; 228 int token = 0; 229 char *format; 230 int error; 231 232 while (tab->name != NULL) { 233 mask = 0; 234 val = 0; 235 format = tab->format; 236 token = 0; 237 error = 0; 238 239 /* 240 * For each entry analyze format strings from the 241 * left (i.e. from the MSB). 242 */ 243 a = (INSN_SIZE * NBBY) - 1; 244 while (*format != '\0' && (a >= 0)) { 245 switch (*format) { 246 case '0': 247 /* Bit is 0, add to mask and pattern */ 248 mask |= (1 << a); 249 a--; 250 format++; 251 break; 252 case '1': 253 /* Bit is 1, add to mask and pattern */ 254 mask |= (1 << a); 255 val |= (1 << a); 256 a--; 257 format++; 258 break; 259 case '|': 260 /* skip */ 261 format++; 262 break; 263 default: 264 /* Token found, copy the name */ 265 memset(tab->tokens[token].name, 0, 266 sizeof(tab->tokens[token].name)); 267 i = 0; 268 while (*format != '(') { 269 tab->tokens[token].name[i] = *format; 270 i++; 271 format++; 272 if (i >= ARM64_MAX_TOKEN_LEN) { 273 printf("ERROR: " 274 "token too long in op %s\n", 275 tab->name); 276 error = 1; 277 break; 278 } 279 } 280 if (error != 0) 281 break; 282 283 /* Read the length value */ 284 ret = sscanf(format, "(%d)", &len); 285 if (ret == 1) { 286 if (token >= ARM64_MAX_TOKEN_CNT) { 287 printf("ERROR: " 288 "too many tokens in op %s\n", 289 tab->name); 290 error = 1; 291 break; 292 } 293 294 a -= len; 295 tab->tokens[token].pos = a + 1; 296 tab->tokens[token].len = len; 297 token++; 298 } 299 300 /* Skip to the end of the token */ 301 while (*format != 0 && *format != '|') 302 format++; 303 } 304 } 305 306 /* Write mask and pattern to the instruction array */ 307 tab->mask = mask; 308 tab->pattern = val; 309 310 /* 311 * If we got here, format string must be parsed and "a" 312 * should point to -1. If it's not, wrong number of bits 313 * in format string. Mark this as invalid and prevent 314 * from being matched. 315 */ 316 if (*format != 0 || (a != -1) || (error != 0)) { 317 tab->mask = 0; 318 tab->pattern = 0xffffffff; 319 printf("ERROR: skipping instruction op %s\n", 320 tab->name); 321 } 322 323 tab++; 324 } 325 } 326 327 static int 328 arm64_disasm_read_token(struct arm64_insn *insn, u_int opcode, 329 const char *token, int *val) 330 { 331 int i; 332 333 for (i = 0; i < ARM64_MAX_TOKEN_CNT; i++) { 334 if (strcmp(insn->tokens[i].name, token) == 0) { 335 *val = (opcode >> insn->tokens[i].pos & 336 ((1 << insn->tokens[i].len) - 1)); 337 return (0); 338 } 339 } 340 341 return (EINVAL); 342 } 343 344 static int 345 arm64_disasm_read_token_sign_ext(struct arm64_insn *insn, u_int opcode, 346 const char *token, int *val) 347 { 348 int i; 349 int msk; 350 351 for (i = 0; i < ARM64_MAX_TOKEN_CNT; i++) { 352 if (strcmp(insn->tokens[i].name, token) == 0) { 353 msk = (1 << insn->tokens[i].len) - 1; 354 *val = ((opcode >> insn->tokens[i].pos) & msk); 355 356 /* If last bit is 1, sign-extend the value */ 357 if (*val & (1 << (insn->tokens[i].len - 1))) 358 *val |= ~msk; 359 360 return (0); 361 } 362 } 363 364 return (EINVAL); 365 } 366 367 static const char * 368 arm64_w_reg(int num, int wsp) 369 { 370 if (num == 31) 371 return (wsp != 0 ? "wsp" : "wzr"); 372 return (w_reg[num]); 373 } 374 375 static const char * 376 arm64_x_reg(int num, int sp) 377 { 378 if (num == 31) 379 return (sp != 0 ? "sp" : "xzr"); 380 return (x_reg[num]); 381 } 382 383 static const char * 384 arm64_reg(int b64, int num, int sp) 385 { 386 if (b64 != 0) 387 return (arm64_x_reg(num, sp)); 388 return (arm64_w_reg(num, sp)); 389 } 390 391 vm_offset_t 392 disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt) 393 { 394 struct arm64_insn *i_ptr = arm64_i; 395 uint32_t insn; 396 int matchp; 397 int ret; 398 int shift, rm, rt, rd, rn, imm, sf, idx, option, scale, amount; 399 int sign_ext; 400 int rm_absent; 401 /* Indicate if immediate should be outside or inside brackets */ 402 int inside; 403 /* Print exclamation mark if pre-incremented */ 404 int pre; 405 /* Indicate if x31 register should be printed as sp or xzr */ 406 int rm_sp, rt_sp, rd_sp, rn_sp; 407 408 /* Initialize defaults, all are 0 except SF indicating 64bit access */ 409 shift = rd = rm = rn = imm = idx = option = amount = scale = 0; 410 sign_ext = 0; 411 sf = 1; 412 413 matchp = 0; 414 insn = di->di_readword(loc); 415 while (i_ptr->name) { 416 /* If mask is 0 then the parser was not initialized yet */ 417 if ((i_ptr->mask != 0) && 418 ((insn & i_ptr->mask) == i_ptr->pattern)) { 419 matchp = 1; 420 break; 421 } 422 i_ptr++; 423 } 424 if (matchp == 0) 425 goto undefined; 426 427 /* Global options */ 428 if (i_ptr->special_ops & OP_SF32) 429 sf = 0; 430 431 /* Global optional tokens */ 432 arm64_disasm_read_token(i_ptr, insn, "SF", &sf); 433 if (i_ptr->special_ops & OP_SF_INV) 434 sf = 1 - sf; 435 if (arm64_disasm_read_token(i_ptr, insn, "SIGN", &sign_ext) == 0) 436 sign_ext = 1 - sign_ext; 437 if (i_ptr->special_ops & OP_SIGN_EXT) 438 sign_ext = 1; 439 if (sign_ext != 0) 440 arm64_disasm_read_token_sign_ext(i_ptr, insn, "IMM", &imm); 441 else 442 arm64_disasm_read_token(i_ptr, insn, "IMM", &imm); 443 if (i_ptr->special_ops & OP_MULT_4) 444 imm <<= 2; 445 446 rm_sp = i_ptr->special_ops & OP_RM_SP; 447 rt_sp = i_ptr->special_ops & OP_RT_SP; 448 rd_sp = i_ptr->special_ops & OP_RD_SP; 449 rn_sp = i_ptr->special_ops & OP_RN_SP; 450 451 /* Print opcode by type */ 452 switch (i_ptr->type) { 453 case TYPE_01: 454 /* 455 * OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #<imm>} SF32/64 456 * OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64 457 */ 458 459 /* Mandatory tokens */ 460 ret = arm64_disasm_read_token(i_ptr, insn, "RD", &rd); 461 ret |= arm64_disasm_read_token(i_ptr, insn, "RN", &rn); 462 if (ret != 0) { 463 printf("ERROR: " 464 "Missing mandatory token for op %s type %d\n", 465 i_ptr->name, i_ptr->type); 466 goto undefined; 467 } 468 469 /* Optional tokens */ 470 arm64_disasm_read_token(i_ptr, insn, "SHIFT", &shift); 471 rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm); 472 473 di->di_printf("%s\t%s, %s", i_ptr->name, 474 arm64_reg(sf, rd, rd_sp), arm64_reg(sf, rn, rn_sp)); 475 476 /* If RM is present use it, otherwise use immediate notation */ 477 if (rm_absent == 0) { 478 di->di_printf(", %s", arm64_reg(sf, rm, rm_sp)); 479 if (imm != 0) 480 di->di_printf(", %s #%d", shift_2[shift], imm); 481 } else { 482 if (imm != 0 || shift != 0) 483 di->di_printf(", #0x%x", imm); 484 if (shift != 0) 485 di->di_printf(" LSL #12"); 486 } 487 break; 488 case TYPE_02: 489 /* 490 * OP <RT>, [<RN>, #<imm>]{!}] SF32/64 491 * OP <RT>, [<RN>], #<imm>{!} SF32/64 492 * OP <RT>, <RN>, <RM> {, EXTEND AMOUNT } 493 */ 494 495 /* Mandatory tokens */ 496 ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt); 497 ret |= arm64_disasm_read_token(i_ptr, insn, "RN", &rn); 498 if (ret != 0) { 499 printf("ERROR: " 500 "Missing mandatory token for op %s type %d\n", 501 i_ptr->name, i_ptr->type); 502 goto undefined; 503 } 504 505 /* Optional tokens */ 506 arm64_disasm_read_token(i_ptr, insn, "OPTION", &option); 507 arm64_disasm_read_token(i_ptr, insn, "SCALE", &scale); 508 rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm); 509 510 if (rm_absent) { 511 /* 512 * In unsigned operation, shift immediate value 513 * and reset options to default. 514 */ 515 if (sign_ext == 0) { 516 imm = imm << ((insn >> ARM_INSN_SIZE_OFFSET) & 517 ARM_INSN_SIZE_MASK); 518 option = 0; 519 } 520 switch (option) { 521 case 0x0: 522 pre = 0; 523 inside = 1; 524 break; 525 case 0x1: 526 pre = 0; 527 inside = 0; 528 break; 529 case 0x2: 530 default: 531 pre = 1; 532 inside = 1; 533 break; 534 } 535 536 di->di_printf("%s\t%s, ", i_ptr->name, 537 arm64_reg(sf, rt, rt_sp)); 538 if (inside != 0) { 539 di->di_printf("[%s", arm64_reg(1, rn, rn_sp)); 540 if (imm != 0) 541 di->di_printf(", #%d", imm); 542 di->di_printf("]"); 543 } else { 544 di->di_printf("[%s]", arm64_reg(1, rn, rn_sp)); 545 if (imm != 0) 546 di->di_printf(", #%d", imm); 547 } 548 if (pre != 0) 549 di->di_printf("!"); 550 } else { 551 /* Last bit of option field determines 32/64 bit offset */ 552 di->di_printf("%s\t%s, [%s, %s", i_ptr->name, 553 arm64_reg(sf, rt, rt_sp), arm64_reg(1, rn, rn_sp), 554 arm64_reg(option & 1, rm, rm_sp)); 555 556 if (scale == 0) 557 amount = 0; 558 else { 559 /* Calculate amount, it's op(31:30) */ 560 amount = (insn >> ARM_INSN_SIZE_OFFSET) & 561 ARM_INSN_SIZE_MASK; 562 } 563 564 switch (option) { 565 case 0x2: 566 di->di_printf(", uxtw #%d", amount); 567 break; 568 case 0x3: 569 if (scale != 0) 570 di->di_printf(", lsl #%d", amount); 571 break; 572 case 0x6: 573 di->di_printf(", sxtw #%d", amount); 574 break; 575 case 0x7: 576 di->di_printf(", sxtx #%d", amount); 577 break; 578 default: 579 di->di_printf(", RSVD"); 580 break; 581 } 582 di->di_printf("]"); 583 } 584 585 break; 586 587 case TYPE_03: 588 /* OP <RT>, #imm SF32/64 */ 589 590 /* Mandatory tokens */ 591 ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt); 592 if (ret != 0) { 593 printf("ERROR: " 594 "Missing mandatory token for op %s type %d\n", 595 i_ptr->name, i_ptr->type); 596 goto undefined; 597 } 598 599 di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt, rt_sp)); 600 if (i_ptr->special_ops & OP_LITERAL) 601 di->di_printf("0x%lx", loc + imm); 602 else 603 di->di_printf("#%d", imm); 604 605 break; 606 default: 607 goto undefined; 608 } 609 610 di->di_printf("\n"); 611 return (loc + INSN_SIZE); 612 613 undefined: 614 di->di_printf("undefined\t%08x\n", insn); 615 return (loc + INSN_SIZE); 616 } 617 618 /* Parse format strings at the very beginning */ 619 SYSINIT(arm64_disasm_generate_masks, SI_SUB_DDB_SERVICES, SI_ORDER_FIRST, 620 arm64_disasm_generate_masks, arm64_i); 621