2 * Copyright (c) 2016 Cavium
5 * This software was developed by Semihalf.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
35 #include <machine/armreg.h>
36 #include <machine/disassem.h>
40 #define ARM64_MAX_TOKEN_LEN 8
41 #define ARM64_MAX_TOKEN_CNT 10
43 #define ARM_INSN_SIZE_OFFSET 30
44 #define ARM_INSN_SIZE_MASK 0x3
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 #define OP_SHIFT_ROR (1UL << 11) /* Use ror shift type */
58 static const char *w_reg[] = {
59 "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
60 "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
61 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
62 "w24", "w25", "w26", "w27", "w28", "w29", "w30"
65 static const char *x_reg[] = {
66 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
67 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
68 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
69 "x24", "x25", "x26", "x27", "x28", "x29", "lr"
72 static const char *shift_2[] = {
73 "lsl", "lsr", "asr", "ror"
77 * Structure representing single token (operand) inside instruction.
78 * name - name of operand
79 * pos - position within the instruction (in bits)
80 * len - operand length (in bits)
82 struct arm64_insn_token {
83 char name[ARM64_MAX_TOKEN_LEN];
89 * Define generic types for instruction printing.
91 enum arm64_format_type {
93 * OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #imm} SF32/64
94 * OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64
95 * OP <RD>, <RM> {, <shift> #<imm> }
96 * OP <RN>, <RM> {, <shift> #<imm> }
101 * OP <RT>, [<RN>, #<imm>]{!} SF32/64
102 * OP <RT>, [<RN>], #<imm>{!} SF32/64
103 * OP <RT>, <RN>, <RM> {, EXTEND AMOUNT }
107 /* OP <RT>, #imm SF32/64 */
112 * Structure representing single parsed instruction format.
114 * format - opcode format in a human-readable way
115 * type - syntax type for printing
116 * special_ops - special options passed to a printer (if any)
117 * mask - bitmask for instruction matching
118 * pattern - pattern to look for
119 * tokens - array of tokens (operands) inside instruction
124 enum arm64_format_type type;
125 uint64_t special_ops;
128 struct arm64_insn_token tokens[ARM64_MAX_TOKEN_CNT];
132 * Specify instruction opcode format in a human-readable way. Use notation
133 * obtained from ARM Architecture Reference Manual for ARMv8-A.
135 * Format string description:
136 * Each group must be separated by "|". Group made of 0/1 is used to
137 * generate mask and pattern for instruction matching. Groups containing
138 * an operand token (in format NAME(length_bits)) are used to retrieve any
139 * operand data from the instruction. Names here must be meaningful
140 * and match the one described in the Manual.
143 * SF - "0" represents 32-bit access, "1" represents 64-bit access
144 * SHIFT - type of shift (instruction dependent)
145 * IMM - immediate value
146 * Rx - register number
147 * OPTION - command specific options
148 * SCALE - scaling of immediate value
150 static struct arm64_insn arm64_i[] = {
151 { "add", "SF(1)|0001011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
152 TYPE_01, 0 }, /* add shifted register */
153 { "mov", "SF(1)|001000100000000000000|RN(5)|RD(5)",
154 TYPE_01, OP_RD_SP | OP_RN_SP }, /* mov (to/from sp) */
155 { "add", "SF(1)|0010001|SHIFT(2)|IMM(12)|RN(5)|RD(5)",
156 TYPE_01, OP_RD_SP | OP_RN_SP }, /* add immediate */
157 { "cmn", "SF(1)|0101011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|11111",
158 TYPE_01, 0 }, /* cmn shifted register */
159 { "adds", "SF(1)|0101011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
160 TYPE_01, 0 }, /* adds shifted register */
161 { "ldr", "1|SF(1)|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)",
162 TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* ldr immediate post/pre index */
163 { "ldr", "1|SF(1)|11100101|IMM(12)|RN(5)|RT(5)",
164 TYPE_02, OP_RN_SP }, /* ldr immediate unsigned */
165 { "ldr", "1|SF(1)|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
166 TYPE_02, OP_RN_SP }, /* ldr register */
167 { "ldr", "0|SF(1)|011000|IMM(19)|RT(5)",
168 TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */
169 { "ldrb", "00|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)",
170 TYPE_02, OP_SIGN_EXT | OP_SF32 | OP_RN_SP },
171 /* ldrb immediate post/pre index */
172 { "ldrb", "00|11100101|IMM(12)|RN(5)|RT(5)",
173 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrb immediate unsigned */
174 { "ldrb", "00|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
175 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrb register */
176 { "ldrh", "01|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", TYPE_02,
177 OP_SIGN_EXT | OP_SF32 | OP_RN_SP }, /* ldrh immediate post/pre index */
178 { "ldrh", "01|11100101|IMM(12)|RN(5)|RT(5)",
179 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrh immediate unsigned */
180 { "ldrh", "01|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
181 TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrh register */
182 { "ldrsb", "001110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)",
183 TYPE_02, OP_SIGN_EXT | OP_SF_INV | OP_RN_SP },
184 /* ldrsb immediate post/pre index */
185 { "ldrsb", "001110011|SF(1)|IMM(12)|RN(5)|RT(5)",\
186 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsb immediate unsigned */
187 { "ldrsb", "001110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
188 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsb register */
189 { "ldrsh", "011110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)",
190 TYPE_02, OP_SIGN_EXT | OP_SF_INV | OP_RN_SP },
191 /* ldrsh immediate post/pre index */
192 { "ldrsh", "011110011|SF(1)|IMM(12)|RN(5)|RT(5)",
193 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsh immediate unsigned */
194 { "ldrsh", "011110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
195 TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsh register */
196 { "ldrsw", "10111000100|IMM(9)|OPTION(2)|RN(5)|RT(5)",
197 TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* ldrsw immediate post/pre index */
198 { "ldrsw", "1011100110|IMM(12)|RN(5)|RT(5)",
199 TYPE_02, OP_RN_SP }, /* ldrsw immediate unsigned */
200 { "ldrsw", "10111000101|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
201 TYPE_02, OP_RN_SP }, /* ldrsw register */
202 { "ldrsw", "10011000|IMM(19)|RT(5)",
203 TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldrsw literal */
204 { "str", "1|SF(1)|111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)",
205 TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* str immediate post/pre index */
206 { "str", "1|SF(1)|11100100|IMM(12)|RN(5)|RT(5)",
207 TYPE_02, OP_RN_SP }, /* str immediate unsigned */
208 { "str", "1|SF(1)|111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
209 TYPE_02, OP_RN_SP }, /* str register */
210 { "strb", "00111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)",
211 TYPE_02, OP_SIGN_EXT | OP_SF32 | OP_RN_SP },
212 /* strb immediate post/pre index */
213 { "strb", "0011100100|IMM(12)|RN(5)|RT(5)",
214 TYPE_02, OP_SF32 | OP_RN_SP }, /* strb immediate unsigned */
215 { "strb", "00111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
216 TYPE_02, OP_SF32 | OP_RN_SP }, /* strb register */
217 { "strh", "01111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)",
218 TYPE_02, OP_SF32 | OP_SIGN_EXT | OP_RN_SP },
219 /* strh immediate post/pre index */
220 { "strh", "0111100100|IMM(12)|RN(5)|RT(5)",
221 TYPE_02, OP_SF32 | OP_RN_SP },
222 /* strh immediate unsigned */
223 { "strh", "01111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
224 TYPE_02, OP_SF32 | OP_RN_SP },
226 { "neg", "SF(1)|1001011|SHIFT(2)|0|RM(5)|IMM(6)|11111|RD(5)",
227 TYPE_01, 0 }, /* neg shifted register */
228 { "sub", "SF(1)|1001011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
229 TYPE_01, 0 }, /* sub shifted register */
230 { "cmp", "SF(1)|1101011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|11111",
231 TYPE_01, 0 }, /* cmp shifted register */
232 { "negs", "SF(1)|1101011|SHIFT(2)|0|RM(5)|IMM(6)|11111|RD(5)",
233 TYPE_01, 0 }, /* negs shifted register */
234 { "subs", "SF(1)|1101011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
235 TYPE_01, 0 }, /* subs shifted register */
236 { "mvn", "SF(1)|0101010|SHIFT(2)|1|RM(5)|IMM(6)|11111|RD(5)",
237 TYPE_01, OP_SHIFT_ROR }, /* mvn shifted register */
238 { "orn", "SF(1)|0101010|SHIFT(2)|1|RM(5)|IMM(6)|RN(5)|RD(5)",
239 TYPE_01, OP_SHIFT_ROR }, /* orn shifted register */
240 { "mov", "SF(1)|0101010000|RM(5)|000000|11111|RD(5)",
241 TYPE_01, 0 }, /* mov register */
242 { "orr", "SF(1)|0101010|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
243 TYPE_01, OP_SHIFT_ROR }, /* orr shifted register */
244 { "and", "SF(1)|0001010|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
245 TYPE_01, OP_SHIFT_ROR }, /* and shifted register */
246 { "tst", "SF(1)|1101010|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|11111",
247 TYPE_01, OP_SHIFT_ROR }, /* tst shifted register */
248 { "ands", "SF(1)|1101010|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
249 TYPE_01, OP_SHIFT_ROR }, /* ands shifted register */
250 { "bic", "SF(1)|0001010|SHIFT(2)|1|RM(5)|IMM(6)|RN(5)|RD(5)",
251 TYPE_01, OP_SHIFT_ROR }, /* bic shifted register */
252 { "bics", "SF(1)|1101010|SHIFT(2)|1|RM(5)|IMM(6)|RN(5)|RD(5)",
253 TYPE_01, OP_SHIFT_ROR }, /* bics shifted register */
254 { "eon", "SF(1)|1001010|SHIFT(2)|1|RM(5)|IMM(6)|RN(5)|RD(5)",
255 TYPE_01, OP_SHIFT_ROR }, /* eon shifted register */
256 { "eor", "SF(1)|1001010|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
257 TYPE_01, OP_SHIFT_ROR }, /* eor shifted register */
262 arm64_disasm_generate_masks(struct arm64_insn *tab)
271 while (tab->name != NULL) {
274 format = tab->format;
279 * For each entry analyze format strings from the
280 * left (i.e. from the MSB).
282 a = (INSN_SIZE * NBBY) - 1;
283 while (*format != '\0' && (a >= 0)) {
286 /* Bit is 0, add to mask and pattern */
292 /* Bit is 1, add to mask and pattern */
303 /* Token found, copy the name */
304 memset(tab->tokens[token].name, 0,
305 sizeof(tab->tokens[token].name));
307 while (*format != '(') {
308 tab->tokens[token].name[i] = *format;
311 if (i >= ARM64_MAX_TOKEN_LEN) {
313 "token too long in op %s\n",
322 /* Read the length value */
323 ret = sscanf(format, "(%d)", &len);
325 if (token >= ARM64_MAX_TOKEN_CNT) {
327 "too many tokens in op %s\n",
334 tab->tokens[token].pos = a + 1;
335 tab->tokens[token].len = len;
339 /* Skip to the end of the token */
340 while (*format != 0 && *format != '|')
345 /* Write mask and pattern to the instruction array */
350 * If we got here, format string must be parsed and "a"
351 * should point to -1. If it's not, wrong number of bits
352 * in format string. Mark this as invalid and prevent
353 * from being matched.
355 if (*format != 0 || (a != -1) || (error != 0)) {
357 tab->pattern = 0xffffffff;
358 printf("ERROR: skipping instruction op %s\n",
367 arm64_disasm_read_token(struct arm64_insn *insn, u_int opcode,
368 const char *token, int *val)
372 for (i = 0; i < ARM64_MAX_TOKEN_CNT; i++) {
373 if (strcmp(insn->tokens[i].name, token) == 0) {
374 *val = (opcode >> insn->tokens[i].pos &
375 ((1 << insn->tokens[i].len) - 1));
384 arm64_disasm_read_token_sign_ext(struct arm64_insn *insn, u_int opcode,
385 const char *token, int *val)
390 for (i = 0; i < ARM64_MAX_TOKEN_CNT; i++) {
391 if (strcmp(insn->tokens[i].name, token) == 0) {
392 msk = (1 << insn->tokens[i].len) - 1;
393 *val = ((opcode >> insn->tokens[i].pos) & msk);
395 /* If last bit is 1, sign-extend the value */
396 if (*val & (1 << (insn->tokens[i].len - 1)))
407 arm64_w_reg(int num, int wsp)
410 return (wsp != 0 ? "wsp" : "wzr");
415 arm64_x_reg(int num, int sp)
418 return (sp != 0 ? "sp" : "xzr");
423 arm64_reg(int b64, int num, int sp)
426 return (arm64_x_reg(num, sp));
427 return (arm64_w_reg(num, sp));
431 disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
433 struct arm64_insn *i_ptr = arm64_i;
437 int shift, rm, rt, rd, rn, imm, sf, idx, option, scale, amount;
439 bool rm_absent, rd_absent, rn_absent;
440 /* Indicate if immediate should be outside or inside brackets */
442 /* Print exclamation mark if pre-incremented */
444 /* Indicate if x31 register should be printed as sp or xzr */
445 int rm_sp, rt_sp, rd_sp, rn_sp;
446 /* Indicate if shift type ror is supported */
449 /* Initialize defaults, all are 0 except SF indicating 64bit access */
450 shift = rd = rm = rn = imm = idx = option = amount = scale = 0;
455 insn = di->di_readword(loc);
456 while (i_ptr->name) {
457 /* If mask is 0 then the parser was not initialized yet */
458 if ((i_ptr->mask != 0) &&
459 ((insn & i_ptr->mask) == i_ptr->pattern)) {
469 if (i_ptr->special_ops & OP_SF32)
472 /* Global optional tokens */
473 arm64_disasm_read_token(i_ptr, insn, "SF", &sf);
474 if (i_ptr->special_ops & OP_SF_INV)
476 if (arm64_disasm_read_token(i_ptr, insn, "SIGN", &sign_ext) == 0)
477 sign_ext = 1 - sign_ext;
478 if (i_ptr->special_ops & OP_SIGN_EXT)
481 arm64_disasm_read_token_sign_ext(i_ptr, insn, "IMM", &imm);
483 arm64_disasm_read_token(i_ptr, insn, "IMM", &imm);
484 if (i_ptr->special_ops & OP_MULT_4)
487 rm_sp = i_ptr->special_ops & OP_RM_SP;
488 rt_sp = i_ptr->special_ops & OP_RT_SP;
489 rd_sp = i_ptr->special_ops & OP_RD_SP;
490 rn_sp = i_ptr->special_ops & OP_RN_SP;
492 has_shift_ror = i_ptr->special_ops & OP_SHIFT_ROR;
494 /* Print opcode by type */
495 switch (i_ptr->type) {
498 * OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #<imm>} SF32/64
499 * OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64
500 * OP <RD>, <RM> {, <shift> #<imm> }
501 * OP <RN>, <RM> {, <shift> #<imm> }
504 rd_absent = arm64_disasm_read_token(i_ptr, insn, "RD", &rd);
505 rn_absent = arm64_disasm_read_token(i_ptr, insn, "RN", &rn);
506 rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm);
507 arm64_disasm_read_token(i_ptr, insn, "SHIFT", &shift);
510 * if shift type is RESERVED for shifted register instruction,
513 if (shift == 3 && !has_shift_ror)
516 di->di_printf("%s\t", i_ptr->name);
519 * If RD and RN are present, we will display the following
521 * - OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #<imm>} SF32/64
522 * - OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64
523 * Otherwise if only RD is present:
524 * - OP <RD>, <RM> {, <shift> #<imm> }
525 * Otherwise if only RN is present:
526 * - OP <RN>, <RM> {, <shift> #<imm> }
528 if (!rd_absent && !rn_absent)
529 di->di_printf("%s, %s", arm64_reg(sf, rd, rd_sp),
530 arm64_reg(sf, rn, rn_sp));
532 di->di_printf("%s", arm64_reg(sf, rd, rd_sp));
534 di->di_printf("%s", arm64_reg(sf, rn, rn_sp));
536 /* If RM is present use it, otherwise use immediate notation */
538 di->di_printf(", %s", arm64_reg(sf, rm, rm_sp));
540 di->di_printf(", %s #%d", shift_2[shift], imm);
542 if (imm != 0 || shift != 0)
543 di->di_printf(", #0x%x", imm);
545 di->di_printf(" lsl #12");
550 * OP <RT>, [<RN>, #<imm>]{!}] SF32/64
551 * OP <RT>, [<RN>], #<imm>{!} SF32/64
552 * OP <RT>, <RN>, <RM> {, EXTEND AMOUNT }
555 /* Mandatory tokens */
556 ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt);
557 ret |= arm64_disasm_read_token(i_ptr, insn, "RN", &rn);
560 "Missing mandatory token for op %s type %d\n",
561 i_ptr->name, i_ptr->type);
565 /* Optional tokens */
566 arm64_disasm_read_token(i_ptr, insn, "OPTION", &option);
567 arm64_disasm_read_token(i_ptr, insn, "SCALE", &scale);
568 rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm);
572 * In unsigned operation, shift immediate value
573 * and reset options to default.
576 imm = imm << ((insn >> ARM_INSN_SIZE_OFFSET) &
596 di->di_printf("%s\t%s, ", i_ptr->name,
597 arm64_reg(sf, rt, rt_sp));
599 di->di_printf("[%s", arm64_reg(1, rn, rn_sp));
601 di->di_printf(", #%d", imm);
604 di->di_printf("[%s]", arm64_reg(1, rn, rn_sp));
606 di->di_printf(", #%d", imm);
611 /* Last bit of option field determines 32/64 bit offset */
612 di->di_printf("%s\t%s, [%s, %s", i_ptr->name,
613 arm64_reg(sf, rt, rt_sp), arm64_reg(1, rn, rn_sp),
614 arm64_reg(option & 1, rm, rm_sp));
619 /* Calculate amount, it's op(31:30) */
620 amount = (insn >> ARM_INSN_SIZE_OFFSET) &
626 di->di_printf(", uxtw #%d", amount);
630 di->di_printf(", lsl #%d", amount);
633 di->di_printf(", sxtw #%d", amount);
636 di->di_printf(", sxtx #%d", amount);
639 di->di_printf(", rsv");
648 /* OP <RT>, #imm SF32/64 */
650 /* Mandatory tokens */
651 ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt);
654 "Missing mandatory token for op %s type %d\n",
655 i_ptr->name, i_ptr->type);
659 di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt, rt_sp));
660 if (i_ptr->special_ops & OP_LITERAL)
661 di->di_printf("0x%lx", loc + imm);
663 di->di_printf("#%d", imm);
671 return (loc + INSN_SIZE);
674 di->di_printf("undefined\t%08x\n", insn);
675 return (loc + INSN_SIZE);
678 /* Parse format strings at the very beginning */
679 SYSINIT(arm64_disasm_generate_masks, SI_SUB_DDB_SERVICES, SI_ORDER_FIRST,
680 arm64_disasm_generate_masks, arm64_i);