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$"); 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 } 476