2 * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
5 * Portions of this software were developed by SRI International and the
6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
9 * Portions of this software were developed by the University of Cambridge
10 * Computer Laboratory as part of the CTSRD Project, with support from the
11 * UK Higher Education Innovation Fund (HEIF).
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <ddb/db_access.h>
42 #include <ddb/db_sym.h>
44 #include <machine/riscvreg.h>
45 #include <machine/riscv_opcode.h>
53 int funct7; /* Or imm, depending on type. */
57 * Keep sorted by opcode, funct3, funct7 so some instructions
58 * aliases will be supported (e.g. "mv" instruction alias)
59 * Use same print format as binutils do.
61 static struct riscv_op riscv_opcodes[] = {
62 { "lb", "I", "d,o(s)", 3, 0, -1 },
63 { "lh", "I", "d,o(s)", 3, 1, -1 },
64 { "lw", "I", "d,o(s)", 3, 2, -1 },
65 { "ld", "I", "d,o(s)", 3, 3, -1 },
66 { "lbu", "I", "d,o(s)", 3, 4, -1 },
67 { "lhu", "I", "d,o(s)", 3, 5, -1 },
68 { "lwu", "I", "d,o(s)", 3, 6, -1 },
69 { "ldu", "I", "d,o(s)", 3, 7, -1 },
70 { "fence", "I", "", 15, 0, -1 },
71 { "fence.i", "I", "", 15, 1, -1 },
72 { "mv", "I", "d,s", 19, 0, 0 },
73 { "addi", "I", "d,s,j", 19, 0, -1 },
74 { "slli", "R2", "d,s,>", 19, 1, 0 },
75 { "slti", "I", "d,s,j", 19, 2, -1 },
76 { "sltiu", "I", "d,s,j", 19, 3, -1 },
77 { "xori", "I", "d,s,j", 19, 4, -1 },
78 { "srli", "R2", "d,s,>", 19, 5, 0 },
79 { "srai", "R2", "d,s,>", 19, 5, 0b010000 },
80 { "ori", "I", "d,s,j", 19, 6, -1 },
81 { "andi", "I", "d,s,j", 19, 7, -1 },
82 { "auipc", "U", "d,u", 23, -1, -1 },
83 { "sext.w", "I", "d,s", 27, 0, 0 },
84 { "addiw", "I", "d,s,j", 27, 0, -1 },
85 { "slliw", "R", "d,s,<", 27, 1, 0 },
86 { "srliw", "R", "d,s,<", 27, 5, 0 },
87 { "sraiw", "R", "d,s,<", 27, 5, 0b0100000 },
88 { "sb", "S", "t,q(s)", 35, 0, -1 },
89 { "sh", "S", "t,q(s)", 35, 1, -1 },
90 { "sw", "S", "t,q(s)", 35, 2, -1 },
91 { "sd", "S", "t,q(s)", 35, 3, -1 },
92 { "sbu", "S", "t,q(s)", 35, 4, -1 },
93 { "shu", "S", "t,q(s)", 35, 5, -1 },
94 { "swu", "S", "t,q(s)", 35, 6, -1 },
95 { "sdu", "S", "t,q(s)", 35, 7, -1 },
96 { "lr.w", "R", "d,t,0(s)", 47, 2, 0b0001000 },
97 { "sc.w", "R", "d,t,0(s)", 47, 2, 0b0001100 },
98 { "amoswap.w", "R", "d,t,0(s)", 47, 2, 0b0000100 },
99 { "amoadd.w", "R", "d,t,0(s)", 47, 2, 0b0000000 },
100 { "amoxor.w", "R", "d,t,0(s)", 47, 2, 0b0010000 },
101 { "amoand.w", "R", "d,t,0(s)", 47, 2, 0b0110000 },
102 { "amoor.w", "R", "d,t,0(s)", 47, 2, 0b0100000 },
103 { "amomin.w", "R", "d,t,0(s)", 47, 2, 0b1000000 },
104 { "amomax.w", "R", "d,t,0(s)", 47, 2, 0b1010000 },
105 { "amominu.w", "R", "d,t,0(s)", 47, 2, 0b1100000 },
106 { "amomaxu.w", "R", "d,t,0(s)", 47, 2, 0b1110000 },
107 { "lr.w.aq", "R", "d,t,0(s)", 47, 2, 0b0001000 },
108 { "sc.w.aq", "R", "d,t,0(s)", 47, 2, 0b0001100 },
109 { "amoswap.w.aq","R", "d,t,0(s)", 47, 2, 0b0000110 },
110 { "amoadd.w.aq","R", "d,t,0(s)", 47, 2, 0b0000010 },
111 { "amoxor.w.aq","R", "d,t,0(s)", 47, 2, 0b0010010 },
112 { "amoand.w.aq","R", "d,t,0(s)", 47, 2, 0b0110010 },
113 { "amoor.w.aq", "R", "d,t,0(s)", 47, 2, 0b0100010 },
114 { "amomin.w.aq","R", "d,t,0(s)", 47, 2, 0b1000010 },
115 { "amomax.w.aq","R", "d,t,0(s)", 47, 2, 0b1010010 },
116 { "amominu.w.aq","R", "d,t,0(s)", 47, 2, 0b1100010 },
117 { "amomaxu.w.aq","R", "d,t,0(s)", 47, 2, 0b1110010 },
118 { "amoswap.w.rl","R", "d,t,0(s)", 47, 2, 0b0000110 },
119 { "amoadd.w.rl","R", "d,t,0(s)", 47, 2, 0b0000001 },
120 { "amoxor.w.rl","R", "d,t,0(s)", 47, 2, 0b0010001 },
121 { "amoand.w.rl","R", "d,t,0(s)", 47, 2, 0b0110001 },
122 { "amoor.w.rl", "R", "d,t,0(s)", 47, 2, 0b0100001 },
123 { "amomin.w.rl","R", "d,t,0(s)", 47, 2, 0b1000001 },
124 { "amomax.w.rl","R", "d,t,0(s)", 47, 2, 0b1010001 },
125 { "amominu.w.rl","R", "d,t,0(s)", 47, 2, 0b1100001 },
126 { "amomaxu.w.rl","R", "d,t,0(s)", 47, 2, 0b1110001 },
127 { "amoswap.d", "R", "d,t,0(s)", 47, 3, 0b0000100 },
128 { "amoadd.d", "R", "d,t,0(s)", 47, 3, 0b0000000 },
129 { "amoxor.d", "R", "d,t,0(s)", 47, 3, 0b0010000 },
130 { "amoand.d", "R", "d,t,0(s)", 47, 3, 0b0110000 },
131 { "amoor.d", "R", "d,t,0(s)", 47, 3, 0b0100000 },
132 { "amomin.d", "R", "d,t,0(s)", 47, 3, 0b1000000 },
133 { "amomax.d", "R", "d,t,0(s)", 47, 3, 0b1010000 },
134 { "amominu.d", "R", "d,t,0(s)", 47, 3, 0b1100000 },
135 { "amomaxu.d", "R", "d,t,0(s)", 47, 3, 0b1110000 },
136 { "lr.d.aq", "R", "d,t,0(s)", 47, 3, 0b0001000 },
137 { "sc.d.aq", "R", "d,t,0(s)", 47, 3, 0b0001100 },
138 { "amoswap.d.aq","R", "d,t,0(s)", 47, 3, 0b0000110 },
139 { "amoadd.d.aq","R", "d,t,0(s)", 47, 3, 0b0000010 },
140 { "amoxor.d.aq","R", "d,t,0(s)", 47, 3, 0b0010010 },
141 { "amoand.d.aq","R", "d,t,0(s)", 47, 3, 0b0110010 },
142 { "amoor.d.aq", "R", "d,t,0(s)", 47, 3, 0b0100010 },
143 { "amomin.d.aq","R", "d,t,0(s)", 47, 3, 0b1000010 },
144 { "amomax.d.aq","R", "d,t,0(s)", 47, 3, 0b1010010 },
145 { "amominu.d.aq","R", "d,t,0(s)", 47, 3, 0b1100010 },
146 { "amomaxu.d.aq","R", "d,t,0(s)", 47, 3, 0b1110010 },
147 { "amoswap.d.rl","R", "d,t,0(s)", 47, 3, 0b0000110 },
148 { "amoadd.d.rl","R", "d,t,0(s)", 47, 3, 0b0000001 },
149 { "amoxor.d.rl","R", "d,t,0(s)", 47, 3, 0b0010001 },
150 { "amoand.d.rl","R", "d,t,0(s)", 47, 3, 0b0110001 },
151 { "amoor.d.rl", "R", "d,t,0(s)", 47, 3, 0b0100001 },
152 { "amomin.d.rl","R", "d,t,0(s)", 47, 3, 0b1000001 },
153 { "amomax.d.rl","R", "d,t,0(s)", 47, 3, 0b1010001 },
154 { "amominu.d.rl","R", "d,t,0(s)", 47, 3, 0b1100001 },
155 { "amomaxu.d.rl","R", "d,t,0(s)", 47, 3, 0b1110001 },
156 { "add", "R", "d,s,t", 51, 0, 0 },
157 { "sub", "R", "d,s,t", 51, 0, 0b0100000 },
158 { "mul", "R", "d,s,t", 51, 0, 0b0000001 },
159 { "sll", "R", "d,s,t", 51, 1, 0 },
160 { "slt", "R", "d,s,t", 51, 2, 0 },
161 { "sltu", "R", "d,s,t", 51, 3, 0 },
162 { "xor", "R", "d,s,t", 51, 4, 0 },
163 { "srl", "R", "d,s,t", 51, 5, 0 },
164 { "sra", "R", "d,s,t", 51, 5, 0b0100000 },
165 { "or", "R", "d,s,t", 51, 6, 0 },
166 { "and", "R", "d,s,t", 51, 7, 0 },
167 { "lui", "U", "d,u", 55, -1, -1 },
168 { "addw", "R", "d,s,t", 59, 0, 0 },
169 { "subw", "R", "d,s,t", 59, 0, 0b0100000 },
170 { "mulw", "R", "d,s,t", 59, 0, 1 },
171 { "sllw", "R", "d,s,t", 59, 1, 0 },
172 { "srlw", "R", "d,s,t", 59, 5, 0 },
173 { "sraw", "R", "d,s,t", 59, 5, 0b0100000 },
174 { "beq", "SB", "s,t,p", 99, 0, -1 },
175 { "bne", "SB", "s,t,p", 99, 1, -1 },
176 { "blt", "SB", "s,t,p", 99, 4, -1 },
177 { "bge", "SB", "s,t,p", 99, 5, -1 },
178 { "bltu", "SB", "s,t,p", 99, 6, -1 },
179 { "bgeu", "SB", "s,t,p", 99, 7, -1 },
180 { "jalr", "I", "d,s,j", 103, 0, -1 },
181 { "jal", "UJ", "a", 111, -1, -1 },
182 { "eret", "I", "", 115, 0, 0b000100000000 },
183 { "sfence.vm", "I", "", 115, 0, 0b000100000001 },
184 { "wfi", "I", "", 115, 0, 0b000100000010 },
185 { "csrrw", "I", "d,E,s", 115, 1, -1},
186 { "csrrs", "I", "d,E,s", 115, 2, -1},
187 { "csrrc", "I", "d,E,s", 115, 3, -1},
188 { "csrrwi", "I", "d,E,Z", 115, 5, -1},
189 { "csrrsi", "I", "d,E,Z", 115, 6, -1},
190 { "csrrci", "I", "d,E,Z", 115, 7, -1},
191 { NULL, NULL, NULL, 0, 0, 0 }
199 static struct csr_op csr_name[] = {
205 { "instret", 0xc02 },
217 { "uarch10", 0xcca },
218 { "uarch11", 0xccb },
219 { "uarch12", 0xccc },
220 { "uarch13", 0xccd },
221 { "uarch14", 0xcce },
222 { "uarch15", 0xccf },
223 { "sstatus", 0x100 },
226 { "sscratch", 0x140 },
233 { "instretw", 0x902 },
236 { "sbadaddr", 0xd43 },
238 { "mstatus", 0x300 },
240 { "mtdeleg", 0x302 },
242 { "mtimecmp", 0x321 },
243 { "mscratch", 0x340 },
246 { "mbadaddr", 0x343 },
251 { "mhartid", 0xf10 },
252 { "mtohost", 0x780 },
253 { "mfromhost", 0x781 },
255 { "send_ipi", 0x783 },
256 { "miobase", 0x784 },
259 { "instreth", 0xc82 },
260 { "cyclehw", 0x980 },
262 { "instrethw", 0x982 },
264 { "stimehw", 0xa81 },
265 { "mtimecmph", 0x361 },
270 static char *reg_name[32] = {
271 "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
272 "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
273 "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
274 "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
278 get_imm(InstFmt i, char *type, uint32_t *val)
284 if (strcmp(type, "I") == 0) {
288 imm |= (0xfffff << 12); /* sign extend */
290 } else if (strcmp(type, "S") == 0) {
291 imm = i.SType.imm0_4;
292 imm |= (i.SType.imm5_11 << 5);
295 imm |= (0xfffff << 12); /* sign extend */
297 } else if (strcmp(type, "U") == 0) {
298 imm = i.UType.imm12_31;
301 } else if (strcmp(type, "UJ") == 0) {
302 imm = i.UJType.imm12_19 << 12;
303 imm |= i.UJType.imm11 << 11;
304 imm |= i.UJType.imm1_10 << 1;
305 imm |= i.UJType.imm20 << 20;
308 imm |= (0xfff << 21); /* sign extend */
310 } else if (strcmp(type, "SB") == 0) {
311 imm = i.SBType.imm11 << 11;
312 imm |= i.SBType.imm1_4 << 1;
313 imm |= i.SBType.imm5_10 << 5;
314 imm |= i.SBType.imm12 << 12;
317 imm |= (0xfffff << 12); /* sign extend */
324 oprint(struct riscv_op *op, vm_offset_t loc, int rd,
325 int rs1, int rs2, uint32_t val, vm_offset_t imm)
332 db_printf("%s\t", op->name);
335 if (strncmp("d", p, 1) == 0)
336 db_printf("%s", reg_name[rd]);
338 else if (strncmp("s", p, 1) == 0)
339 db_printf("%s", reg_name[rs1]);
341 else if (strncmp("t", p, 1) == 0)
342 db_printf("%s", reg_name[rs2]);
344 else if (strncmp(">", p, 1) == 0)
345 db_printf("0x%x", rs2);
347 else if (strncmp("E", p, 1) == 0) {
348 for (i = 0; csr_name[i].name != NULL; i++)
349 if (csr_name[i].imm == val)
352 } else if (strncmp("Z", p, 1) == 0)
353 db_printf("%d", rs1);
355 else if (strncmp("<", p, 1) == 0)
356 db_printf("0x%x", rs2);
358 else if (strncmp("j", p, 1) == 0)
359 db_printf("%d", imm);
361 else if (strncmp("u", p, 1) == 0)
362 db_printf("0x%x", imm);
364 else if (strncmp("a", p, 1) == 0)
365 db_printf("0x%016lx", imm);
367 else if (strncmp("p", p, 1) == 0)
368 db_printf("0x%016lx", (loc + imm));
370 else if (strlen(p) >= 4) {
371 if (strncmp("o(s)", p, 4) == 0)
372 db_printf("%d(%s)", imm, reg_name[rs1]);
373 else if (strncmp("q(s)", p, 4) == 0)
374 db_printf("%d(%s)", imm, reg_name[rs1]);
375 else if (strncmp("0(s)", p, 4) == 0)
376 db_printf("(%s)", reg_name[rs1]);
379 while (*p && strncmp(p, ",", 1) != 0)
393 match_type(InstFmt i, struct riscv_op *op, vm_offset_t loc)
400 imm = get_imm(i, op->type, &val);
402 if (strcmp(op->type, "U") == 0) {
403 oprint(op, loc, i.UType.rd, 0, 0, val, imm);
406 if (strcmp(op->type, "UJ") == 0) {
407 oprint(op, loc, 0, 0, 0, val, (loc + imm));
410 if ((strcmp(op->type, "I") == 0) && \
411 (op->funct3 == i.IType.funct3)) {
413 if (op->funct7 != -1) {
414 if (op->funct7 == i.IType.imm)
420 oprint(op, loc, i.IType.rd,
421 i.IType.rs1, 0, val, imm);
425 if ((strcmp(op->type, "S") == 0) && \
426 (op->funct3 == i.SType.funct3)) {
427 oprint(op, loc, 0, i.SType.rs1, i.SType.rs2,
431 if ((strcmp(op->type, "SB") == 0) && \
432 (op->funct3 == i.SBType.funct3)) {
433 oprint(op, loc, 0, i.SBType.rs1, i.SBType.rs2,
437 if ((strcmp(op->type, "R2") == 0) && \
438 (op->funct3 == i.R2Type.funct3) && \
439 (op->funct7 == i.R2Type.funct7)) {
440 oprint(op, loc, i.R2Type.rd, i.R2Type.rs1,
441 i.R2Type.rs2, val, imm);
444 if ((strcmp(op->type, "R") == 0) && \
445 (op->funct3 == i.RType.funct3) && \
446 (op->funct7 == i.RType.funct7)) {
447 oprint(op, loc, i.RType.rd, i.RType.rs1,
448 val, i.RType.rs2, imm);
456 db_disasm(vm_offset_t loc, bool altfmt)
462 i.word = db_get_value(loc, INSN_SIZE, 0);
464 /* First match opcode */
465 for (j = 0; riscv_opcodes[j].name != NULL; j++) {
466 op = &riscv_opcodes[j];
467 if (op->opcode == i.RType.opcode) {
468 if (match_type(i, op, loc))
474 return(loc + INSN_SIZE);