1 /*-
2 * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
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.
8 *
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).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
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.
21 *
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
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD: releng/11.0/sys/riscv/riscv/db_disasm.c 296614 2016-03-10 15:51:43Z br $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <ddb/ddb.h>
41 #include <ddb/db_access.h>
42 #include <ddb/db_sym.h>
43
44 #include <machine/riscvreg.h>
45 #include <machine/riscv_opcode.h>
46
47 struct riscv_op {
48 char *name;
49 char *type;
50 char *fmt;
51 int opcode;
52 int funct3;
53 int funct7; /* Or imm, depending on type. */
54 };
55
56 /*
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.
60 */
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 }
192 };
193
194 struct csr_op {
195 char *name;
196 int imm;
197 };
198
199 static struct csr_op csr_name[] = {
200 { "fflags", 0x001 },
201 { "frm", 0x002 },
202 { "fcsr", 0x003 },
203 { "cycle", 0xc00 },
204 { "time", 0xc01 },
205 { "instret", 0xc02 },
206 { "stats", 0x0c0 },
207 { "uarch0", 0xcc0 },
208 { "uarch1", 0xcc1 },
209 { "uarch2", 0xcc2 },
210 { "uarch3", 0xcc3 },
211 { "uarch4", 0xcc4 },
212 { "uarch5", 0xcc5 },
213 { "uarch6", 0xcc6 },
214 { "uarch7", 0xcc7 },
215 { "uarch8", 0xcc8 },
216 { "uarch9", 0xcc9 },
217 { "uarch10", 0xcca },
218 { "uarch11", 0xccb },
219 { "uarch12", 0xccc },
220 { "uarch13", 0xccd },
221 { "uarch14", 0xcce },
222 { "uarch15", 0xccf },
223 { "sstatus", 0x100 },
224 { "stvec", 0x101 },
225 { "sie", 0x104 },
226 { "sscratch", 0x140 },
227 { "sepc", 0x141 },
228 { "sip", 0x144 },
229 { "sptbr", 0x180 },
230 { "sasid", 0x181 },
231 { "cyclew", 0x900 },
232 { "timew", 0x901 },
233 { "instretw", 0x902 },
234 { "stime", 0xd01 },
235 { "scause", 0xd42 },
236 { "sbadaddr", 0xd43 },
237 { "stimew", 0xa01 },
238 { "mstatus", 0x300 },
239 { "mtvec", 0x301 },
240 { "mtdeleg", 0x302 },
241 { "mie", 0x304 },
242 { "mtimecmp", 0x321 },
243 { "mscratch", 0x340 },
244 { "mepc", 0x341 },
245 { "mcause", 0x342 },
246 { "mbadaddr", 0x343 },
247 { "mip", 0x344 },
248 { "mtime", 0x701 },
249 { "mcpuid", 0xf00 },
250 { "mimpid", 0xf01 },
251 { "mhartid", 0xf10 },
252 { "mtohost", 0x780 },
253 { "mfromhost", 0x781 },
254 { "mreset", 0x782 },
255 { "send_ipi", 0x783 },
256 { "miobase", 0x784 },
257 { "cycleh", 0xc80 },
258 { "timeh", 0xc81 },
259 { "instreth", 0xc82 },
260 { "cyclehw", 0x980 },
261 { "timehw", 0x981 },
262 { "instrethw", 0x982 },
263 { "stimeh", 0xd81 },
264 { "stimehw", 0xa81 },
265 { "mtimecmph", 0x361 },
266 { "mtimeh", 0x741 },
267 { NULL, 0 }
268 };
269
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"
275 };
276
277 static int32_t
278 get_imm(InstFmt i, char *type, uint32_t *val)
279 {
280 int imm;
281
282 imm = 0;
283
284 if (strcmp(type, "I") == 0) {
285 imm = i.IType.imm;
286 *val = imm;
287 if (imm & (1 << 11))
288 imm |= (0xfffff << 12); /* sign extend */
289
290 } else if (strcmp(type, "S") == 0) {
291 imm = i.SType.imm0_4;
292 imm |= (i.SType.imm5_11 << 5);
293 *val = imm;
294 if (imm & (1 << 11))
295 imm |= (0xfffff << 12); /* sign extend */
296
297 } else if (strcmp(type, "U") == 0) {
298 imm = i.UType.imm12_31;
299 *val = imm;
300
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;
306 *val = imm;
307 if (imm & (1 << 20))
308 imm |= (0xfff << 21); /* sign extend */
309
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;
315 *val = imm;
316 if (imm & (1 << 12))
317 imm |= (0xfffff << 12); /* sign extend */
318 }
319
320 return (imm);
321 }
322
323 static int
324 oprint(struct riscv_op *op, vm_offset_t loc, int rd,
325 int rs1, int rs2, uint32_t val, vm_offset_t imm)
326 {
327 char *p;
328 int i;
329
330 p = op->fmt;
331
332 db_printf("%s\t", op->name);
333
334 while (*p) {
335 if (strncmp("d", p, 1) == 0)
336 db_printf("%s", reg_name[rd]);
337
338 else if (strncmp("s", p, 1) == 0)
339 db_printf("%s", reg_name[rs1]);
340
341 else if (strncmp("t", p, 1) == 0)
342 db_printf("%s", reg_name[rs2]);
343
344 else if (strncmp(">", p, 1) == 0)
345 db_printf("0x%x", rs2);
346
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)
350 db_printf("%s",
351 csr_name[i].name);
352 } else if (strncmp("Z", p, 1) == 0)
353 db_printf("%d", rs1);
354
355 else if (strncmp("<", p, 1) == 0)
356 db_printf("0x%x", rs2);
357
358 else if (strncmp("j", p, 1) == 0)
359 db_printf("%d", imm);
360
361 else if (strncmp("u", p, 1) == 0)
362 db_printf("0x%x", imm);
363
364 else if (strncmp("a", p, 1) == 0)
365 db_printf("0x%016lx", imm);
366
367 else if (strncmp("p", p, 1) == 0)
368 db_printf("0x%016lx", (loc + imm));
369
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]);
377 }
378
379 while (*p && strncmp(p, ",", 1) != 0)
380 p++;
381
382 if (*p) {
383 db_printf(", ");
384 p++;
385 }
386 }
387
388
389 return (0);
390 }
391
392 static int
393 match_type(InstFmt i, struct riscv_op *op, vm_offset_t loc)
394 {
395 uint32_t val;
396 int found;
397 int imm;
398
399 val = 0;
400 imm = get_imm(i, op->type, &val);
401
402 if (strcmp(op->type, "U") == 0) {
403 oprint(op, loc, i.UType.rd, 0, 0, val, imm);
404 return (1);
405 }
406 if (strcmp(op->type, "UJ") == 0) {
407 oprint(op, loc, 0, 0, 0, val, (loc + imm));
408 return (1);
409 }
410 if ((strcmp(op->type, "I") == 0) && \
411 (op->funct3 == i.IType.funct3)) {
412 found = 0;
413 if (op->funct7 != -1) {
414 if (op->funct7 == i.IType.imm)
415 found = 1;
416 } else
417 found = 1;
418
419 if (found) {
420 oprint(op, loc, i.IType.rd,
421 i.IType.rs1, 0, val, imm);
422 return (1);
423 }
424 }
425 if ((strcmp(op->type, "S") == 0) && \
426 (op->funct3 == i.SType.funct3)) {
427 oprint(op, loc, 0, i.SType.rs1, i.SType.rs2,
428 val, imm);
429 return (1);
430 }
431 if ((strcmp(op->type, "SB") == 0) && \
432 (op->funct3 == i.SBType.funct3)) {
433 oprint(op, loc, 0, i.SBType.rs1, i.SBType.rs2,
434 val, imm);
435 return (1);
436 }
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);
442 return (1);
443 }
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);
449 return (1);
450 }
451
452 return (0);
453 }
454
455 vm_offset_t
456 db_disasm(vm_offset_t loc, bool altfmt)
457 {
458 struct riscv_op *op;
459 InstFmt i;
460 int j;
461
462 i.word = db_get_value(loc, INSN_SIZE, 0);
463
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))
469 break;
470 }
471 }
472
473 db_printf("\n");
474 return(loc + INSN_SIZE);
475 }
Cache object: 685c43033696767de229244e70883bd6
|