1 /* $NetBSD: db_disasm.c,v 1.13 2024/11/24 19:41:18 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 __RCSID("$NetBSD: db_disasm.c,v 1.13 2024/11/24 19:41:18 skrll Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 39 #include <riscv/db_machdep.h> 40 #include <riscv/frame.h> 41 #include <riscv/insn.h> 42 43 #include <ddb/db_access.h> 44 #include <ddb/db_user.h> 45 #include <ddb/db_interface.h> 46 #include <ddb/db_output.h> 47 #include <ddb/db_extern.h> 48 #include <ddb/db_sym.h> 49 50 //////////////////////////////////////////////////////////// 51 // registers 52 53 static const char *riscv_registers[32] = { 54 "zero", "ra", "sp", "gp", "tp", 55 "t0", "t1", "t2", 56 "s0", "s1", 57 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", 58 "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", 59 "t3", "t4", "t5", "t6" 60 }; 61 62 /* XXX this should be in MI ddb */ 63 static void 64 db_print_addr(db_addr_t loc) 65 { 66 db_expr_t diff; 67 db_sym_t sym; 68 const char *symname; 69 70 /* hack for testing since the test program is ASLR'd */ 71 #ifndef _KERNEL 72 loc &= 0xfff; 73 #endif 74 75 diff = INT_MAX; 76 symname = NULL; 77 sym = db_search_symbol(loc, DB_STGY_ANY, &diff); 78 db_symbol_values(sym, &symname, 0); 79 80 if (symname) { 81 if (diff == 0) 82 db_printf("%s", symname); 83 else 84 db_printf("<%s+%"DDB_EXPR_FMT"x>", symname, diff); 85 db_printf("\t[addr:%#"PRIxVADDR"]", loc); 86 } else { 87 db_printf("%#"PRIxVADDR, loc); 88 } 89 } 90 91 //////////////////////////////////////////////////////////// 92 // 16-bit instructions 93 94 /* 95 * This is too tightly wedged in to make it worth trying to make it 96 * table-driven. But I'm going to hack it up to use a 1-level switch. 97 * 98 * Note that quite a few instructions depend on the architecture word 99 * size. I've used the #defines for that to conditionalize it, on the 100 * grounds that ddb is disassembling itself so the build machine 101 * version is the target machine version. This is not true for crash 102 * necessarily but I don't think 103 */ 104 105 #define COMBINE(op, q) (((op) << 2) | (q)) 106 107 #define IN_Q0(op) COMBINE(op, OPCODE16_Q0) 108 #define IN_Q1(op) COMBINE(op, OPCODE16_Q1) 109 #define IN_Q2(op) COMBINE(op, OPCODE16_Q2) 110 111 /* 112 * All the 16-bit immediate bit-wrangling is done in uint32_t, which 113 * is sufficient, but on RV64 the resulting values should be printed 114 * as 64-bit. Continuing the assumption that we're disassembling for 115 * the size we're built on, do nothing for RV32 and sign-extend from 116 * 32 to 64 for RV64. (And bail on RV128 since it's not clear what 117 * the C type sizes are going to be there anyway...) 118 */ 119 static unsigned long 120 maybe_signext64(uint32_t x) 121 { 122 #if __riscv_xlen == 32 123 return x; 124 #elif __riscv_xlen == 64 125 uint64_t xx; 126 127 xx = ((x & 0x80000000) ? 0xffffffff00000000 : 0) | x; 128 return xx; 129 #else 130 #error Oops. 131 #endif 132 } 133 134 static int 135 db_disasm_16(db_addr_t loc, uint32_t insn, bool altfmt) 136 { 137 /* note: insn needs to be uint32_t for immediate computations */ 138 139 uint32_t imm; 140 unsigned rd, rs1, rs2; 141 142 switch (COMBINE(INSN16_FUNCT3(insn), INSN16_QUADRANT(insn))) { 143 case IN_Q0(Q0_ADDI4SPN): 144 rd = INSN16_RS2x(insn); 145 imm = INSN16_IMM_CIW(insn); 146 if (imm == 0) { 147 /* reserved (all bits 0 -> invalid) */ 148 return EINVAL; 149 } 150 db_printf("c.addi4spn %s, 0x%x\n", riscv_registers[rd], imm); 151 break; 152 case IN_Q0(Q0_FLD_LQ): 153 rs1 = INSN16_RS1x(insn); 154 rd = INSN16_RS2x(insn); 155 #if __riscv_xlen < 128 156 imm = INSN16_IMM_CL_D(insn); 157 db_printf("c.fld f%d, %d(%s)\n", rd, (int32_t)imm, 158 riscv_registers[rs1]); 159 #else 160 imm = INSN16_IMM_CL_Q(insn); 161 db_printf("c.lq %s, %d(%s)\n", riscv_registers[rd], 162 (int32_t)imm, riscv_registers[rs1]); 163 #endif 164 break; 165 case IN_Q0(Q0_LW): 166 rs1 = INSN16_RS1x(insn); 167 rd = INSN16_RS2x(insn); 168 imm = INSN16_IMM_CL_W(insn); 169 db_printf("c.lw %s, %d(%s)\n", riscv_registers[rd], 170 (int32_t)imm, riscv_registers[rs1]); 171 break; 172 case IN_Q0(Q0_FLW_LD): 173 rs1 = INSN16_RS1x(insn); 174 rd = INSN16_RS2x(insn); 175 #if __riscv_xlen == 32 176 imm = INSN16_IMM_CL_W(insn); 177 db_printf("c.flw f%d, %d(%s)\n", rd, (int32_t)imm, 178 riscv_registers[rs1]); 179 #else 180 imm = INSN16_IMM_CL_D(insn); 181 db_printf("c.ld %s, %d(%s)\n", riscv_registers[rd], 182 (int32_t)imm, riscv_registers[rs1]); 183 #endif 184 break; 185 case IN_Q0(Q0_FSD_SQ): 186 rs1 = INSN16_RS1x(insn); 187 rs2 = INSN16_RS2x(insn); 188 #if __riscv_xlen < 128 189 imm = INSN16_IMM_CS_D(insn); 190 db_printf("c.fsd f%d, %d(%s)\n", rs2, (int32_t)imm, 191 riscv_registers[rs1]); 192 #else 193 imm = INSN16_IMM_CS_Q(insn); 194 db_printf("c.sq %s, %d(%s)\n", riscv_registers[rs2], 195 (int32_t)imm, riscv_registers[rs1]); 196 #endif 197 break; 198 case IN_Q0(Q0_SW): 199 rs1 = INSN16_RS1x(insn); 200 rs2 = INSN16_RS2x(insn); 201 imm = INSN16_IMM_CS_W(insn); 202 db_printf("c.sw %s, %d(%s)\n", riscv_registers[rs2], 203 (int32_t)imm, riscv_registers[rs1]); 204 break; 205 case IN_Q0(Q0_FSW_SD): 206 rs1 = INSN16_RS1x(insn); 207 rs2 = INSN16_RS2x(insn); 208 #if __riscv_xlen == 32 209 imm = INSN16_IMM_CS_W(insn); 210 db_printf("c.fsw f%d, %d(%s)\n", rs2, (int32_t)imm, 211 riscv_registers[rs1]); 212 #else 213 imm = INSN16_IMM_CS_D(insn); 214 db_printf("c.sd %s, %d(%s)\n", riscv_registers[rs2], 215 (int32_t)imm, riscv_registers[rs1]); 216 #endif 217 break; 218 case IN_Q1(Q1_NOP_ADDI): 219 rd = INSN16_RS1(insn); 220 imm = INSN16_IMM_CI_K(insn); 221 if (rd == 0 && imm == 0) { 222 db_printf("c.nop\n"); 223 } else if (rd == 0 && imm != 0) { 224 /* undefined hint */ 225 return EINVAL; 226 } else if (rd != 0 && imm == 0) { 227 /* undefined hint */ 228 return EINVAL; 229 } else { 230 db_printf("c.addi %s, %s, 0x%lx\n", 231 riscv_registers[rd], 232 riscv_registers[rd], 233 maybe_signext64(imm)); 234 } 235 break; 236 case IN_Q1(Q1_JAL_ADDIW): 237 #if __riscv_xlen == 32 238 imm = INSN16_IMM_CJ(insn); 239 db_printf("c.jal "); 240 db_print_addr(loc + (int32_t)imm); 241 db_printf("\n"); 242 #else 243 rd = INSN16_RS1(insn); 244 imm = INSN16_IMM_CI_K(insn); 245 db_printf("c.addiw %s, %s, 0x%lx\n", riscv_registers[rd], 246 riscv_registers[rd], maybe_signext64(imm)); 247 #endif 248 break; 249 case IN_Q1(Q1_LI): 250 rd = INSN16_RS1(insn); 251 imm = INSN16_IMM_CI_K(insn); 252 db_printf("c.li %s, 0x%lx\n", riscv_registers[rd], 253 maybe_signext64(imm)); 254 break; 255 case IN_Q1(Q1_ADDI16SP_LUI): 256 rd = INSN16_RS1(insn); 257 if (rd == 2/*sp*/) { 258 imm = INSN16_IMM_CI_K4(insn); 259 db_printf("c.add16sp sp, 0x%lx\n", 260 maybe_signext64(imm)); 261 } 262 else { 263 imm = INSN16_IMM_CI_K12(insn); 264 db_printf("c.lui %s, 0x%lx\n", riscv_registers[rd], 265 maybe_signext64(imm)); 266 } 267 break; 268 case IN_Q1(Q1_MISC): 269 imm = INSN16_IMM_CI_K(insn); 270 rd = INSN16_RS1x(insn); 271 switch (INSN16_FUNCT2a(insn)) { 272 case Q1MISC_SRLI: 273 case Q1MISC_SRAI: 274 #if __riscv_xlen == 32 275 if (imm > 31) { 276 /* reserved */ 277 return EINVAL; 278 } 279 #elif __riscv_xlen == 64 280 /* drop the sign-extension */ 281 imm &= 63; 282 #elif __riscv_xlen == 128 283 if (imm == 0) { 284 imm = 64; 285 } 286 else { 287 imm &= 127; 288 } 289 #endif 290 db_printf("c.%s %s, %d\n", 291 INSN16_FUNCT2a(insn) == Q1MISC_SRLI ? 292 "srli" : "srai", 293 riscv_registers[rd], imm); 294 break; 295 case Q1MISC_ANDI: 296 db_printf("c.andi %s, 0x%lx\n", riscv_registers[rd], 297 maybe_signext64(imm)); 298 break; 299 case Q1MISC_MORE: 300 rs2 = INSN16_RS2x(insn); 301 switch (INSN16_FUNCT3c(insn)) { 302 case Q1MORE_SUB: 303 db_printf("c.sub"); 304 break; 305 case Q1MORE_XOR: 306 db_printf("c.xor"); 307 break; 308 case Q1MORE_OR: 309 db_printf("c.or"); 310 break; 311 case Q1MORE_AND: 312 db_printf("c.and"); 313 break; 314 case Q1MORE_SUBW: 315 db_printf("c.subw"); 316 break; 317 case Q1MORE_ADDW: 318 db_printf("c.addw"); 319 break; 320 default: 321 return EINVAL; 322 } 323 db_printf(" %s, %s, %s\n", riscv_registers[rd], 324 riscv_registers[rd], riscv_registers[rs2]); 325 break; 326 } 327 break; 328 case IN_Q1(Q1_J): 329 imm = INSN16_IMM_CJ(insn); 330 db_printf("c.j "); 331 db_print_addr(loc + (int32_t)imm); 332 db_printf("\n"); 333 break; 334 case IN_Q1(Q1_BEQZ): 335 rs1 = INSN16_RS1x(insn); 336 imm = INSN16_IMM_CB(insn); 337 db_printf("c.beqz %s, ", riscv_registers[rs1]); 338 db_print_addr(loc + (int32_t)imm); 339 db_printf("\n"); 340 break; 341 case IN_Q1(Q1_BNEZ): 342 rs1 = INSN16_RS1x(insn); 343 imm = INSN16_IMM_CB(insn); 344 db_printf("c.bnez %s, ", riscv_registers[rs1]); 345 db_print_addr(loc + (int32_t)imm); 346 db_printf("\n"); 347 break; 348 case IN_Q2(Q2_SLLI): 349 rd = INSN16_RS1(insn); 350 imm = INSN16_IMM_CI_K(insn); 351 #if __riscv_xlen == 32 352 if (imm > 31) { 353 /* reserved */ 354 return EINVAL; 355 } 356 #elif __riscv_xlen == 64 357 /* drop the sign-extension */ 358 imm &= 63; 359 #elif __riscv_xlen == 128 360 if (imm == 0) { 361 imm = 64; 362 } 363 else { 364 /* 365 * XXX the manual is not clear on 366 * whether this is like c.srli/c.srai 367 * or truncates to 6 bits. I'm assuming 368 * the former. 369 */ 370 imm &= 127; 371 } 372 #endif 373 db_printf("c.slli %s, %d\n", riscv_registers[rd], imm); 374 break; 375 case IN_Q2(Q2_FLDSP_LQSP): 376 rd = INSN16_RS1(insn); 377 #if __riscv_xlen < 128 378 imm = INSN16_IMM_CI_D(insn); 379 db_printf("c.fldsp f%d, %d(sp)\n", rd, imm); 380 #else 381 if (rd == 0) { 382 /* reserved */ 383 return EINVAL; 384 } 385 imm = INSN16_IMM_CI_Q(insn); 386 db_printf("c.lqsp %s, %d(sp)\n", riscv_registers[rd], imm); 387 #endif 388 break; 389 case IN_Q2(Q2_LWSP): 390 rd = INSN16_RS1(insn); 391 if (rd == 0) { 392 /* reserved */ 393 return EINVAL; 394 } 395 imm = INSN16_IMM_CI_W(insn); 396 db_printf("c.lwsp %s, %d(sp)\n", riscv_registers[rd], imm); 397 break; 398 case IN_Q2(Q2_FLWSP_LDSP): 399 rd = INSN16_RS1(insn); 400 #if __riscv_xlen == 32 401 imm = INSN16_IMM_CI_W(insn); 402 db_printf("c.flwsp f%d, %d(sp)\n", rd, imm); 403 #else 404 if (rd == 0) { 405 /* reserved */ 406 return EINVAL; 407 } 408 imm = INSN16_IMM_CI_D(insn); 409 db_printf("c.ldsp %s, %d(sp)\n", riscv_registers[rd], imm); 410 #endif 411 break; 412 case IN_Q2(Q2_MISC): 413 rs1 = INSN16_RS1(insn); 414 rs2 = INSN16_RS2(insn); 415 switch (INSN16_FUNCT1b(insn)) { 416 case Q2MISC_JR_MV: 417 if (rs1 == 0) { 418 return EINVAL; 419 } else if (rs2 == 0) { 420 db_printf("c.jr %s\n", riscv_registers[rs1]); 421 } else { 422 db_printf("c.mv %s, %s\n", 423 riscv_registers[rs1], 424 riscv_registers[rs2]); 425 } 426 break; 427 case Q2MISC_EBREAK_JALR_ADD: 428 if (rs1 == 0 && rs2 == 0) { 429 db_printf("c.ebreak\n"); 430 } else if (rs2 == 0) { 431 db_printf("c.jalr %s\n", riscv_registers[rs1]); 432 } else if (rs1 == 0) { 433 return EINVAL; 434 } else { 435 db_printf("c.add %s, %s, %s\n", 436 riscv_registers[rs1], 437 riscv_registers[rs1], 438 riscv_registers[rs2]); 439 } 440 break; 441 } 442 break; 443 case IN_Q2(Q2_FSDSP_SQSP): 444 rs2 = INSN16_RS2(insn); 445 #if __riscv_xlen < 128 446 imm = INSN16_IMM_CSS_D(insn); 447 db_printf("c.fsdsp f%d, %d(sp)\n", rs2, imm); 448 #else 449 imm = INSN16_IMM_CSS_Q(insn); 450 db_printf("c.sqsp %s, %d(sp)\n", riscv_registers[rs2], imm); 451 #endif 452 break; 453 case IN_Q2(Q2_SWSP): 454 rs2 = INSN16_RS2(insn); 455 imm = INSN16_IMM_CSS_W(insn); 456 db_printf("c.swsp %s, %d(sp)\n", riscv_registers[rs2], imm); 457 break; 458 case IN_Q2(Q2_FSWSP_SDSP): 459 rs2 = INSN16_RS2(insn); 460 #if __riscv_xlen == 32 461 imm = INSN16_IMM_CSS_W(insn); 462 db_printf("c.fswsp f%d, %d(sp)\n", rs2, imm); 463 #else 464 imm = INSN16_IMM_CSS_D(insn); 465 db_printf("c.sdsp %s, %d(sp)\n", riscv_registers[rs2], imm); 466 #endif 467 break; 468 default: 469 /* 0b11 marks 32-bit instructions and shouldn't come here */ 470 return EINVAL; 471 } 472 return 0; 473 } 474 475 //////////////////////////////////////////////////////////// 476 // 32-bit instructions 477 478 /* match flags */ 479 #define CHECK_F3 0x0001 /* check funct3 field */ 480 #define CHECK_F7 0x0002 /* check funct7 field */ 481 #define CHECK_F5 0x0004 /* check tpo of funct7 field only */ 482 #define CHECK_RS2 0x0008 /* check rs2 as quaternary opcode */ 483 #define SHIFT32 0x0010 /* 32-bit immediate shift */ 484 #define SHIFT64 0x0020 /* 64-bit immediate shift */ 485 #define RD_0 0x0040 /* rd field should be 0 */ 486 #define RS1_0 0x0080 /* rs1 field should be 0 */ 487 #define RS2_0 0x0100 /* rs2 field should be 0 */ 488 #define IMM_0 0x0200 /* immediate value should be 0 */ 489 #define F3AMO 0x0400 /* expect amo size in funct3 */ 490 #define F3ROUND 0x0800 /* expect fp rounding mode in funct3 */ 491 #define F7SIZE 0x1000 /* expect fp size in funct7:0-1 */ 492 #define RS2_FSIZE 0x2000 /* expect fp size in rs2 */ 493 #define RS2_FSIZE_INT 0x4000 /* expect fp size in rs2 */ 494 #define FENCEFM 0x8000 /* fence mode in top 4 bits of imm */ 495 /* do not add more without increasing the field size below */ 496 497 #ifdef _LP64 /* disassembling ourself so can use our build flags... */ 498 #define SHIFTNATIVE SHIFT64 499 #else 500 #define SHIFTNATIVE SHIFT32 501 #endif 502 503 /* print flags */ 504 #define MEMORYIMM 0x001 /* print immediate as 0(reg) */ 505 #define FENCEIMM 0x002 /* print fence instruction codes */ 506 #define DECIMM 0x004 /* print immediate in decimal */ 507 #define BRANCHIMM 0x008 /* print immediate as branch target */ 508 #define CSRIMM 0x010 /* immediate is csr number */ 509 #define CSRIIMM 0x020 /* ... also an immediate in rs1 */ 510 #define AMOAQRL 0x040 /* print acquire/release bits of amo */ 511 #define RS2SIZE_FIRST 0x080 /* print rs2 size before funct7 size */ 512 #define RD_FREG 0x100 /* rd is a fpu reg */ 513 #define RS1_FREG 0x200 /* rs1 is a fpu reg */ 514 #define RS2_FREG 0x400 /* rs2 is a fpu reg */ 515 #define ISCVT 0x800 /* is an fpu conversion op */ 516 /* do not add more without increasing the field size below */ 517 518 #define ALL_FREG (RD_FREG | RS1_FREG | RS2_FREG) 519 #define RS12_FREG (RS1_FREG | RS2_FREG) 520 521 /* entries for matching within a major opcode */ 522 struct riscv_disasm_insn { 523 const char *name; 524 unsigned int matchflags: 16, 525 funct3: 3, 526 funct7: 7, 527 rs2: 5; 528 unsigned int printflags: 12; 529 }; 530 531 /* format codes */ 532 #define FMT_R 0 533 #define FMT_R4 1 534 #define FMT_I 2 535 #define FMT_In 3 536 #define FMT_S 4 537 #define FMT_B 5 538 #define FMT_U 6 539 #define FMT_J 7 540 #define FMT_UNKNOWN 8 541 #define FMT_ASSERT 9 542 543 /* top-level opcode dispatch */ 544 struct riscv_disasm32_entry { 545 uint8_t fmt; 546 union { 547 // R4, In, U, J 548 const char *name; 549 // R, I, S, B 550 struct { 551 const struct riscv_disasm_insn *v; 552 unsigned n; 553 } entries; 554 } u; 555 }; 556 557 #define INSN_F3(n, f3, moretests, pflags) \ 558 { \ 559 .name = n, \ 560 .matchflags = CHECK_F3 | moretests, \ 561 .funct3 = f3, .funct7 = 0, .rs2 = 0, \ 562 .printflags = pflags, \ 563 } 564 565 #define INSN_F5(n, f5, moretests, pflags) \ 566 { \ 567 .name = n, \ 568 .matchflags = CHECK_F7 | CHECK_F5 | moretests, \ 569 .funct3 = 0, .funct7 = f5 << 2, .rs2 = 0, \ 570 .printflags = pflags, \ 571 } 572 573 #define INSN_F53(n, f5, f3, moretests, pflags) \ 574 { \ 575 .name = n, \ 576 .matchflags = CHECK_F7 | CHECK_F5 | CHECK_F3 | moretests, \ 577 .funct3 = f3, .funct7 = f5 << 2, .rs2 = 0, \ 578 .printflags = pflags, \ 579 } 580 581 #define INSN_F7(n, f7, moretests, pflags) \ 582 { \ 583 .name = n, \ 584 .matchflags = CHECK_F7 | moretests, \ 585 .funct3 = 0, .funct7 = f7, .rs2 = 0, \ 586 .printflags = pflags, \ 587 } 588 589 #define INSN_F73(n, f7, f3, moretests, pflags) \ 590 { \ 591 .name = n, \ 592 .matchflags = CHECK_F7 | CHECK_F3 | moretests, \ 593 .funct3 = f3, .funct7 = f7, .rs2 = 0, \ 594 .printflags = pflags, \ 595 } 596 597 #define INSN_F37(n, f3, f7, moretests, pflags) \ 598 INSN_F73(n, f7, f3, moretests, pflags) 599 600 #define INSN_USER(n, rs2val, moretests, pflags) \ 601 { \ 602 .name = n, \ 603 .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ 604 .funct3 = SYSTEM_PRIV, .funct7 = PRIV_USER, \ 605 .rs2 = rs2val, \ 606 .printflags = pflags, \ 607 } 608 609 #define INSN_SYSTEM(n, rs2val, moretests, pflags) \ 610 { \ 611 .name = n, \ 612 .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ 613 .funct3 = SYSTEM_PRIV, .funct7 = PRIV_SYSTEM, \ 614 .rs2 = rs2val, \ 615 .printflags = pflags, \ 616 } 617 618 #define INSN_MACHINE(n, rs2val, moretests, pflags) \ 619 { \ 620 .name = n, \ 621 .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ 622 .funct3 = SYSTEM_PRIV, .funct7 = PRIV_MACHINE, \ 623 .rs2 = rs2val, \ 624 .printflags = pflags, \ 625 } 626 627 static const struct riscv_disasm_insn riscv_disasm_miscmem[] = { 628 INSN_F3("fence", MISCMEM_FENCE, RD_0 | RS1_0 | FENCEFM, FENCEIMM), 629 INSN_F3("fence.i", MISCMEM_FENCEI, RD_0 | RS1_0 | IMM_0, 0), 630 }; 631 632 static const struct riscv_disasm_insn riscv_disasm_load[] = { 633 INSN_F3("lb", LOAD_LB, 0, MEMORYIMM), 634 INSN_F3("lh", LOAD_LH, 0, MEMORYIMM), 635 INSN_F3("lw", LOAD_LW, 0, MEMORYIMM), 636 INSN_F3("ld", LOAD_LD, 0, MEMORYIMM), 637 INSN_F3("lbu", LOAD_LBU, 0, MEMORYIMM), 638 INSN_F3("lhu", LOAD_LHU, 0, MEMORYIMM), 639 INSN_F3("lwu", LOAD_LWU, 0, MEMORYIMM), 640 }; 641 642 static const struct riscv_disasm_insn riscv_disasm_loadfp[] = { 643 INSN_F3("flw", LOADFP_FLW, 0, MEMORYIMM | RD_FREG), 644 INSN_F3("fld", LOADFP_FLD, 0, MEMORYIMM | RD_FREG), 645 INSN_F3("flq", LOADFP_FLQ, 0, MEMORYIMM | RD_FREG), 646 }; 647 648 static const struct riscv_disasm_insn riscv_disasm_opimm[] = { 649 INSN_F3("nop", OP_ADDSUB, RD_0 | RS1_0 | IMM_0, 0), 650 INSN_F3("addi", OP_ADDSUB, 0, 0), 651 INSN_F3("slti", OP_SLT, 0, 0), 652 INSN_F3("sltiu", OP_SLTU, 0, 0), 653 INSN_F3("xori", OP_XOR, 0, 0), 654 INSN_F3("ori", OP_OR, 0, 0), 655 INSN_F3("andi", OP_AND, 0, 0), 656 INSN_F37("slli", OP_SLL, OP_ARITH, SHIFTNATIVE, DECIMM), 657 INSN_F37("srli", OP_SRX, OP_ARITH, SHIFTNATIVE, DECIMM), 658 INSN_F37("srai", OP_SRX, OP_NARITH, SHIFTNATIVE, DECIMM), 659 }; 660 661 static const struct riscv_disasm_insn riscv_disasm_opimm32[] = { 662 INSN_F3("addiw", OP_ADDSUB, 0, 0), 663 INSN_F37("slliw", OP_SLL, OP_ARITH, SHIFT32, DECIMM), 664 INSN_F37("srliw", OP_SRX, OP_ARITH, SHIFT32, DECIMM), 665 INSN_F37("sraiw", OP_SRX, OP_NARITH, SHIFT32, DECIMM), 666 }; 667 668 static const struct riscv_disasm_insn riscv_disasm_store[] = { 669 INSN_F3("sb", STORE_SB, 0, MEMORYIMM), 670 INSN_F3("sh", STORE_SH, 0, MEMORYIMM), 671 INSN_F3("sw", STORE_SW, 0, MEMORYIMM), 672 INSN_F3("sd", STORE_SD, 0, MEMORYIMM), 673 }; 674 675 static const struct riscv_disasm_insn riscv_disasm_storefp[] = { 676 INSN_F3("fsw", STOREFP_FSW, 0, MEMORYIMM | RS2_FREG), 677 INSN_F3("fsd", STOREFP_FSD, 0, MEMORYIMM | RS2_FREG), 678 INSN_F3("fsq", STOREFP_FSQ, 0, MEMORYIMM | RS2_FREG), 679 }; 680 681 static const struct riscv_disasm_insn riscv_disasm_branch[] = { 682 INSN_F3("beq", BRANCH_BEQ, 0, BRANCHIMM), 683 INSN_F3("bne", BRANCH_BNE, 0, BRANCHIMM), 684 INSN_F3("blt", BRANCH_BLT, 0, BRANCHIMM), 685 INSN_F3("bge", BRANCH_BGE, 0, BRANCHIMM), 686 INSN_F3("bltu", BRANCH_BLTU, 0, BRANCHIMM), 687 INSN_F3("bgeu", BRANCH_BGEU, 0, BRANCHIMM), 688 }; 689 690 static const struct riscv_disasm_insn riscv_disasm_system[] = { 691 INSN_F3("csrw", SYSTEM_CSRRW, RD_0, CSRIMM), 692 INSN_F3("csrrw", SYSTEM_CSRRW, 0, CSRIMM), 693 INSN_F3("csrr", SYSTEM_CSRRS, RS1_0, CSRIMM), 694 INSN_F3("csrrs", SYSTEM_CSRRS, 0, CSRIMM), 695 INSN_F3("csrrc", SYSTEM_CSRRC, 0, CSRIMM), 696 INSN_F3("csrwi", SYSTEM_CSRRWI, RD_0, CSRIIMM), 697 INSN_F3("csrrwi", SYSTEM_CSRRWI, 0, CSRIIMM), 698 INSN_F3("csrrsi", SYSTEM_CSRRSI, 0, CSRIIMM), 699 INSN_F3("csrrci", SYSTEM_CSRRCI, 0, CSRIIMM), 700 INSN_F37("sfence.vma", SYSTEM_PRIV, PRIV_SFENCE_VMA, RD_0, 0), 701 INSN_F37("hfence.bvma", SYSTEM_PRIV, PRIV_HFENCE_BVMA, 0, 0), 702 INSN_F37("hfence.gvma", SYSTEM_PRIV, PRIV_HFENCE_GVMA, 0, 0), 703 INSN_USER("ecall", USER_ECALL, RD_0 | RS1_0, 0), 704 INSN_USER("ebreak", USER_EBREAK, RD_0 | RS1_0, 0), 705 INSN_USER("uret", USER_URET, RD_0 | RS1_0, 0), 706 INSN_SYSTEM("sret", SYSTEM_SRET, RD_0 | RS1_0, 0), 707 INSN_SYSTEM("wfi", SYSTEM_WFI, RD_0 | RS1_0, 0), 708 INSN_MACHINE("mret", MACHINE_MRET, RD_0 | RS1_0, 0), 709 }; 710 711 static const struct riscv_disasm_insn riscv_disasm_amo[] = { 712 INSN_F5("amoadd", AMO_ADD, F3AMO, AMOAQRL), 713 INSN_F5("amoswap", AMO_SWAP, F3AMO, AMOAQRL), 714 INSN_F5("lr", AMO_LR, F3AMO | RS2_0, AMOAQRL), 715 INSN_F5("sc", AMO_SC, F3AMO, AMOAQRL), 716 INSN_F5("amoxor", AMO_XOR, F3AMO, AMOAQRL), 717 INSN_F5("amoor", AMO_OR, F3AMO, AMOAQRL), 718 INSN_F5("amoand", AMO_AND, F3AMO, AMOAQRL), 719 INSN_F5("amomin", AMO_MIN, F3AMO, AMOAQRL), 720 INSN_F5("amomax", AMO_MAX, F3AMO, AMOAQRL), 721 INSN_F5("amominu", AMO_MINU, F3AMO, AMOAQRL), 722 INSN_F5("amomaxu", AMO_MAXU, F3AMO, AMOAQRL), 723 }; 724 725 static const struct riscv_disasm_insn riscv_disasm_op[] = { 726 INSN_F37("add", OP_ADDSUB, OP_ARITH, 0, 0), 727 INSN_F37("sub", OP_ADDSUB, OP_NARITH, 0, 0), 728 INSN_F37("sll", OP_SLL, OP_ARITH, 0, 0), 729 INSN_F37("slt", OP_SLT, OP_ARITH, 0, 0), 730 INSN_F37("sltu", OP_SLTU, OP_ARITH, 0, 0), 731 INSN_F37("xor", OP_XOR, OP_ARITH, 0, 0), 732 INSN_F37("srl", OP_SRX, OP_ARITH, 0, 0), 733 INSN_F37("sra", OP_SRX, OP_NARITH, 0, 0), 734 INSN_F37("or", OP_OR, OP_ARITH, 0, 0), 735 INSN_F37("and", OP_AND, OP_ARITH, 0, 0), 736 INSN_F37("mul", OP_MUL, OP_MULDIV, 0, 0), 737 INSN_F37("mulh", OP_MULH, OP_MULDIV, 0, 0), 738 INSN_F37("mulhsu", OP_MULHSU, OP_MULDIV, 0, 0), 739 INSN_F37("mulhu", OP_MULHU, OP_MULDIV, 0, 0), 740 INSN_F37("div", OP_DIV, OP_MULDIV, 0, 0), 741 INSN_F37("divu", OP_DIVU, OP_MULDIV, 0, 0), 742 INSN_F37("rem", OP_REM, OP_MULDIV, 0, 0), 743 INSN_F37("remu", OP_REMU, OP_MULDIV, 0, 0), 744 }; 745 746 static const struct riscv_disasm_insn riscv_disasm_op32[] = { 747 INSN_F37("addw", OP_ADDSUB, OP_ARITH, 0, 0), 748 INSN_F37("subw", OP_ADDSUB, OP_NARITH, 0, 0), 749 INSN_F37("sllw", OP_SLL, OP_ARITH, 0, 0), 750 INSN_F37("srlw", OP_SRX, OP_ARITH, 0, 0), 751 INSN_F37("sraw", OP_SRX, OP_NARITH, 0, 0), 752 INSN_F37("mulw", OP_MUL, OP_MULDIV, 0, 0), 753 INSN_F37("divw", OP_DIV, OP_MULDIV, 0, 0), 754 INSN_F37("divuw", OP_DIVU, OP_MULDIV, 0, 0), 755 INSN_F37("remw", OP_REM, OP_MULDIV, 0, 0), 756 INSN_F37("remuw", OP_REMU, OP_MULDIV, 0, 0), 757 }; 758 759 static const struct riscv_disasm_insn riscv_disasm_opfp[] = { 760 INSN_F5("fadd", OPFP_ADD, F7SIZE|F3ROUND, ALL_FREG), 761 INSN_F5("fsub", OPFP_SUB, F7SIZE|F3ROUND, ALL_FREG), 762 INSN_F5("fmul", OPFP_MUL, F7SIZE|F3ROUND, ALL_FREG), 763 INSN_F5("fdiv", OPFP_DIV, F7SIZE|F3ROUND, ALL_FREG), 764 INSN_F53("fsgnj", OPFP_SGNJ, SGN_SGNJ, F7SIZE, ALL_FREG), 765 INSN_F53("fsgnjn", OPFP_SGNJ, SGN_SGNJN, F7SIZE, ALL_FREG), 766 INSN_F53("fsgnjx", OPFP_SGNJ, SGN_SGNJX, F7SIZE, ALL_FREG), 767 INSN_F53("fmin", OPFP_MINMAX, MINMAX_MIN, F7SIZE, ALL_FREG), 768 INSN_F53("fmax", OPFP_MINMAX, MINMAX_MAX, F7SIZE, ALL_FREG), 769 INSN_F5("fcvt", OPFP_CVTFF, F7SIZE|F3ROUND|RS2_FSIZE, 770 ISCVT | ALL_FREG), 771 INSN_F5("fsqrt", OPFP_SQRT, F7SIZE|F3ROUND|RS2_0, ALL_FREG), 772 INSN_F53("fle", OPFP_CMP, CMP_LE, F7SIZE, RS12_FREG), 773 INSN_F53("flt", OPFP_CMP, CMP_LT, F7SIZE, RS12_FREG), 774 INSN_F53("feq", OPFP_CMP, CMP_EQ, F7SIZE, RS12_FREG), 775 INSN_F5("fcvt", OPFP_CVTIF, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT, 776 ISCVT | RS2SIZE_FIRST | RS1_FREG), 777 INSN_F5("fcvt", OPFP_CVTFI, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT, 778 ISCVT | RD_FREG), 779 INSN_F53("fclass", OPFP_MVFI_CLASS, MVFI_CLASS_CLASS, F7SIZE|RS2_0, 780 RS1_FREG), 781 INSN_F73("fmv.x.w", (OPFP_MVFI_CLASS << 2) | OPFP_S, MVFI_CLASS_MVFI, 782 RS2_0, RS1_FREG), 783 INSN_F73("fmv.w.x", (OPFP_MVIF << 2) | OPFP_S, 0, 784 RS2_0, RD_FREG), 785 INSN_F73("fmv.x.d", (OPFP_MVFI_CLASS << 2) | OPFP_D, MVFI_CLASS_MVFI, 786 RS2_0, RS1_FREG), 787 INSN_F73("fmv.d.x", (OPFP_MVIF << 2) | OPFP_D, 0, 788 RS2_0, RD_FREG), 789 }; 790 791 #define TABLE(table) \ 792 .u.entries.v = table, .u.entries.n = __arraycount(table) 793 794 static const struct riscv_disasm32_entry riscv_disasm32[32] = { 795 [OPCODE_AUIPC] = { .fmt = FMT_U, .u.name = "auipc" }, 796 [OPCODE_LUI] = { .fmt = FMT_U, .u.name = "lui" }, 797 [OPCODE_JAL] = { .fmt = FMT_J, .u.name = "jal" }, 798 [OPCODE_JALR] = { .fmt = FMT_In, .u.name = "jalr" }, 799 [OPCODE_MISCMEM] = { .fmt = FMT_I, TABLE(riscv_disasm_miscmem) }, 800 [OPCODE_LOAD] = { .fmt = FMT_I, TABLE(riscv_disasm_load) }, 801 [OPCODE_LOADFP] = { .fmt = FMT_I, TABLE(riscv_disasm_loadfp) }, 802 [OPCODE_OPIMM] = { .fmt = FMT_I, TABLE(riscv_disasm_opimm) }, 803 [OPCODE_OPIMM32] = { .fmt = FMT_I, TABLE(riscv_disasm_opimm32) }, 804 [OPCODE_STORE] = { .fmt = FMT_S, TABLE(riscv_disasm_store) }, 805 [OPCODE_STOREFP] = { .fmt = FMT_S, TABLE(riscv_disasm_storefp) }, 806 [OPCODE_BRANCH] = { .fmt = FMT_B, TABLE(riscv_disasm_branch) }, 807 [OPCODE_SYSTEM] = { .fmt = FMT_R, TABLE(riscv_disasm_system) }, 808 [OPCODE_AMO] = { .fmt = FMT_R, TABLE(riscv_disasm_amo) }, 809 [OPCODE_OP] = { .fmt = FMT_R, TABLE(riscv_disasm_op) }, 810 [OPCODE_OP32] = { .fmt = FMT_R, TABLE(riscv_disasm_op32) }, 811 [OPCODE_OPFP] = { .fmt = FMT_R, TABLE(riscv_disasm_opfp) }, 812 [OPCODE_MADD] = { .fmt = FMT_R4, .u.name = "fmadd" }, 813 [OPCODE_MSUB] = { .fmt = FMT_R4, .u.name = "fmsub" }, 814 [OPCODE_NMADD] = { .fmt = FMT_R4, .u.name = "fnmadd" }, 815 [OPCODE_NMSUB] = { .fmt = FMT_R4, .u.name = "fnmsub" }, 816 [OPCODE_CUSTOM0] = { .fmt = FMT_UNKNOWN }, 817 [OPCODE_CUSTOM1] = { .fmt = FMT_UNKNOWN }, 818 [OPCODE_CUSTOM2] = { .fmt = FMT_UNKNOWN }, 819 [OPCODE_CUSTOM3] = { .fmt = FMT_UNKNOWN }, 820 [OPCODE_rsvd21] = { .fmt = FMT_UNKNOWN }, 821 [OPCODE_rsvd26] = { .fmt = FMT_UNKNOWN }, 822 [OPCODE_rsvd29] = { .fmt = FMT_UNKNOWN }, 823 [OPCODE_X48a] = { .fmt = FMT_ASSERT }, 824 [OPCODE_X48b] = { .fmt = FMT_ASSERT }, 825 [OPCODE_X64] = { .fmt = FMT_ASSERT }, 826 [OPCODE_X80] = { .fmt = FMT_ASSERT }, 827 }; 828 829 static const struct riscv_disasm_insn * 830 riscv_disasm_match(const struct riscv_disasm_insn *table, unsigned num, 831 uint32_t insn, uint32_t imm) 832 { 833 unsigned i, f3, f7, testf7; 834 const struct riscv_disasm_insn *info; 835 836 f3 = INSN_FUNCT3(insn); 837 f7 = INSN_FUNCT7(insn); 838 for (i=0; i<num; i++) { 839 info = &table[i]; 840 841 /* always check funct3 first */ 842 if (info->matchflags & CHECK_F3) { 843 if (info->funct3 != f3) { 844 continue; 845 } 846 } 847 848 /* now funct7 */ 849 testf7 = f7; 850 if (info->matchflags & SHIFT64) { 851 /* shift count leaks into the bottom bit of funct7 */ 852 testf7 &= 0b1111110; 853 } 854 if (info->matchflags & CHECK_F5) { 855 /* other stuff in the bottom two bits, don't look */ 856 testf7 &= 0b1111100; 857 } 858 if (info->matchflags & CHECK_F7) { 859 if (info->funct7 != testf7) { 860 continue; 861 } 862 } 863 864 /* finally rs2 as the 4th opcode field */ 865 if (info->matchflags & CHECK_RS2) { 866 if (info->rs2 != INSN_RS2(insn)) { 867 continue; 868 } 869 } 870 871 /* check fields that are supposed to be 0 */ 872 if (info->matchflags & RD_0) { 873 if (INSN_RD(insn) != 0) { 874 continue; 875 } 876 } 877 if (info->matchflags & RS1_0) { 878 if (INSN_RS1(insn) != 0) { 879 continue; 880 } 881 } 882 if (info->matchflags & RS2_0) { 883 /* this could be folded into CHECK_RS2 */ 884 /* (but would make the initializations uglier) */ 885 if (INSN_RS2(insn) != 0) { 886 continue; 887 } 888 } 889 if (info->matchflags & IMM_0) { 890 if (imm != 0) { 891 continue; 892 } 893 } 894 895 /* other checks */ 896 if (info->matchflags & F3AMO) { 897 if (f3 != AMO_W && f3 != AMO_D) { 898 continue; 899 } 900 } 901 if (info->matchflags & F3ROUND) { 902 switch (f3) { 903 case ROUND_RNE: 904 case ROUND_RTZ: 905 case ROUND_RDN: 906 case ROUND_RUP: 907 case ROUND_RMM: 908 case ROUND_DYN: 909 break; 910 default: 911 continue; 912 } 913 } 914 if (info->matchflags & F7SIZE) { 915 /* fpu size bits at bottom of funct7 */ 916 /* always floating sizes */ 917 switch (f7 & 3) { 918 case OPFP_S: 919 case OPFP_D: 920 case OPFP_Q: 921 break; 922 default: 923 continue; 924 } 925 } 926 if (info->matchflags & RS2_FSIZE) { 927 /* fpu size bits in rs2 field */ 928 if (info->matchflags & RS2_FSIZE_INT) { 929 /* integer sizes */ 930 switch (INSN_RS2(insn)) { 931 case OPFP_W: 932 case OPFP_WU: 933 case OPFP_L: 934 case OPFP_LU: 935 break; 936 default: 937 continue; 938 } 939 } 940 else { 941 /* floating sizes */ 942 switch (INSN_RS2(insn)) { 943 case OPFP_S: 944 case OPFP_D: 945 case OPFP_Q: 946 break; 947 default: 948 continue; 949 } 950 } 951 } 952 if (info->matchflags & FENCEFM) { 953 /* imm is 12 bits, upper 4 are a fence mode */ 954 switch (imm >> 8) { 955 case FENCE_FM_NORMAL: 956 case FENCE_FM_TSO: 957 break; 958 default: 959 continue; 960 } 961 } 962 963 /* passed all tests */ 964 return info; 965 } 966 /* no match */ 967 return NULL; 968 } 969 970 static void 971 db_print_riscv_fencebits(unsigned bits) 972 { 973 if (bits == 0) { 974 db_printf("0"); 975 } 976 else { 977 db_printf("%s%s%s%s", 978 (bits & FENCE_INPUT) ? "i" : "", 979 (bits & FENCE_OUTPUT) ? "o" : "", 980 (bits & FENCE_READ) ? "r" : "", 981 (bits & FENCE_WRITE) ? "w" : ""); 982 } 983 } 984 985 static void 986 db_print_riscv_reg(unsigned reg, bool isfreg) 987 { 988 if (isfreg) { 989 db_printf("f%d", reg); 990 } 991 else { 992 db_printf("%s", riscv_registers[reg]); 993 } 994 } 995 996 static const char * 997 riscv_int_size(unsigned fpsize) 998 { 999 switch (fpsize) { 1000 case OPFP_W: return ".w"; 1001 case OPFP_WU: return ".wu"; 1002 case OPFP_L: return ".l"; 1003 case OPFP_LU: return ".lu"; 1004 default: 1005 /* matching should prevent it coming here */ 1006 return ".?"; 1007 } 1008 } 1009 1010 static const char * 1011 riscv_fp_size(unsigned fpsize) 1012 { 1013 switch (fpsize) { 1014 case OPFP_S: return ".s"; 1015 case OPFP_D: return ".d"; 1016 case OPFP_Q: return ".q"; 1017 default: 1018 /* matching should prevent it coming here */ 1019 return ".?"; 1020 } 1021 } 1022 1023 static bool 1024 larger_f_i(unsigned sz1, unsigned sz2) 1025 { 1026 switch (sz1) { 1027 case OPFP_S: 1028 break; 1029 case OPFP_D: 1030 switch (sz2) { 1031 case OPFP_W: 1032 case OPFP_WU: 1033 return true; 1034 default: 1035 break; 1036 } 1037 break; 1038 case OPFP_Q: 1039 switch (sz2) { 1040 case OPFP_W: 1041 case OPFP_WU: 1042 case OPFP_L: 1043 case OPFP_LU: 1044 return true; 1045 default: 1046 break; 1047 } 1048 break; 1049 default: 1050 /* matching should keep it from coming here */ 1051 break; 1052 } 1053 return false; 1054 } 1055 1056 static bool 1057 larger_f_f(unsigned sz1, unsigned sz2) 1058 { 1059 switch (sz1) { 1060 case OPFP_S: 1061 break; 1062 case OPFP_D: 1063 switch (sz2) { 1064 case OPFP_S: 1065 return true; 1066 default: 1067 break; 1068 } 1069 break; 1070 case OPFP_Q: 1071 switch (sz2) { 1072 case OPFP_S: 1073 case OPFP_D: 1074 return true; 1075 default: 1076 break; 1077 } 1078 break; 1079 default: 1080 /* matching should keep it from coming here */ 1081 break; 1082 } 1083 return false; 1084 } 1085 1086 static void 1087 db_print_riscv_fpround(const char *sep, unsigned round) 1088 { 1089 switch (round) { 1090 case ROUND_RNE: db_printf("%srne", sep); break; 1091 case ROUND_RTZ: db_printf("%srtz", sep); break; 1092 case ROUND_RDN: db_printf("%srdn", sep); break; 1093 case ROUND_RUP: db_printf("%srup", sep); break; 1094 case ROUND_RMM: db_printf("%srmm", sep); break; 1095 case ROUND_DYN: break; 1096 default: 1097 /* matching should prevent it coming here */ 1098 db_printf("%s<unknown-rounding-mode>", sep); 1099 break; 1100 } 1101 } 1102 1103 1104 static void 1105 db_print_riscv_insnname(uint32_t insn, const struct riscv_disasm_insn *info) 1106 { 1107 db_printf("%s", info->name); 1108 1109 /* accumulated mode cruft on the name */ 1110 if (info->matchflags & F3AMO) { 1111 db_printf("%s", INSN_FUNCT3(insn) == AMO_W ? ".w" : ".d"); 1112 } 1113 if ((info->matchflags & RS2_FSIZE) && 1114 (info->printflags & RS2SIZE_FIRST)) { 1115 if (info->matchflags & RS2_FSIZE_INT) { 1116 db_printf("%s", riscv_int_size(INSN_RS2(insn))); 1117 } 1118 else { 1119 db_printf("%s", riscv_fp_size(INSN_RS2(insn))); 1120 } 1121 } 1122 if (info->matchflags & F7SIZE) { 1123 db_printf("%s", riscv_fp_size(INSN_FUNCT7(insn) & 3)); 1124 } 1125 if ((info->matchflags & RS2_FSIZE) && 1126 (info->printflags & RS2SIZE_FIRST) == 0) { 1127 if (info->matchflags & RS2_FSIZE_INT) { 1128 db_printf("%s", riscv_int_size(INSN_RS2(insn))); 1129 } 1130 else { 1131 db_printf("%s", riscv_fp_size(INSN_RS2(insn))); 1132 } 1133 } 1134 if (info->matchflags & FENCEFM) { 1135 /* 1136 * The fence mode is the top 4 bits of the instruction, 1137 * which is the top 4 bits of funct7, so get it from 1138 * there. Elsewhere in this file it's defined in terms 1139 * of the immediate though. XXX tidy up 1140 */ 1141 if ((INSN_FUNCT7(insn) >> 3) == FENCE_FM_TSO) { 1142 db_printf(".tso"); 1143 } 1144 } 1145 if (info->printflags & AMOAQRL) { 1146 db_printf("%s%s", 1147 INSN_FUNCT7(insn) & AMO_AQ ? ".aq" : "", 1148 INSN_FUNCT7(insn) & AMO_RL ? ".rl" : ""); 1149 } 1150 } 1151 1152 static int 1153 db_disasm_32(db_addr_t loc, uint32_t insn, bool altfmt) 1154 { 1155 unsigned opcode; 1156 const struct riscv_disasm32_entry *d; 1157 unsigned numtable; 1158 const struct riscv_disasm_insn *table, *info; 1159 const char *sep = " "; 1160 uint32_t imm; 1161 1162 opcode = INSN_OPCODE32(insn); 1163 d = &riscv_disasm32[opcode]; 1164 switch (d->fmt) { 1165 case FMT_R: 1166 /* register ops */ 1167 table = d->u.entries.v; 1168 numtable = d->u.entries.n; 1169 info = riscv_disasm_match(table, numtable, insn, 0); 1170 if (info == NULL) { 1171 return EINVAL; 1172 } 1173 1174 /* name */ 1175 db_print_riscv_insnname(insn, info); 1176 1177 /* rd */ 1178 if ((info->matchflags & RD_0) == 0) { 1179 db_printf("%s", sep); 1180 db_print_riscv_reg(INSN_RD(insn), 1181 info->printflags & RD_FREG); 1182 sep = ", "; 1183 } 1184 1185 if (info->printflags & CSRIMM) { 1186 /* 1187 * CSR instruction; these appear under a major 1188 * opcode with register format, but they 1189 * actually use the I format. Sigh. The 1190 * immediate field contains the CSR number and 1191 * prints _before_ rs1. 1192 */ 1193 imm = INSN_IMM_I(insn); 1194 db_printf("%s0x%x, ", sep, (int32_t)imm); 1195 db_print_riscv_reg(INSN_RS1(insn), 1196 info->printflags & RS1_FREG); 1197 } else if (info->printflags & CSRIIMM) { 1198 /* 1199 * CSR instruction with immediate; the CSR 1200 * number is in the immediate field and the RS1 1201 * field contains the immediate. Bleck. 1202 */ 1203 imm = INSN_IMM_I(insn); 1204 db_printf("%s0x%x, %d", sep, (int32_t)imm, 1205 INSN_RS1(insn)); 1206 } 1207 else { 1208 /* rs1 */ 1209 if ((info->matchflags & RS1_0) == 0) { 1210 db_printf("%s", sep); 1211 db_print_riscv_reg(INSN_RS1(insn), 1212 info->printflags & RS1_FREG); 1213 sep = ", "; 1214 } 1215 1216 /* rs2 */ 1217 if ((info->matchflags & RS2_0) == 0 && 1218 (info->matchflags & CHECK_RS2) == 0 && 1219 (info->matchflags & RS2_FSIZE) == 0) { 1220 db_printf("%s", sep); 1221 db_print_riscv_reg(INSN_RS2(insn), 1222 info->printflags & RS2_FREG); 1223 } 1224 } 1225 1226 if (info->matchflags & F3ROUND) { 1227 /* 1228 * Suppress rounding mode print for insns that 1229 * never round, because gas encodes it as 0 1230 * ("rup") rather than the normal default 1231 * ("dyn"). 1232 * 1233 * These are: convert float to larger float, 1234 * convert int to float larger than the float. 1235 */ 1236 bool suppress; 1237 1238 if (info->printflags & ISCVT) { 1239 if (info->matchflags & RS2SIZE_FIRST) { 1240 /* convert to int */ 1241 suppress = false; 1242 } 1243 else if (info->matchflags & RS2_FSIZE_INT) { 1244 /* convert from int */ 1245 suppress = larger_f_i( 1246 INSN_FUNCT7(insn) & 3, 1247 INSN_RS2(insn)); 1248 } 1249 else { 1250 /* convert from float */ 1251 suppress = larger_f_f( 1252 INSN_FUNCT7(insn) & 3, 1253 INSN_RS2(insn)); 1254 } 1255 } 1256 else { 1257 suppress = false; 1258 } 1259 1260 if (!suppress) { 1261 db_print_riscv_fpround(sep, INSN_FUNCT3(insn)); 1262 } 1263 } 1264 1265 db_printf("\n"); 1266 break; 1267 case FMT_R4: 1268 db_printf("%s%s f%d, f%d, f%d, f%d", d->u.name, 1269 riscv_fp_size(INSN_FUNCT7(insn) & 3), 1270 INSN_RD(insn), 1271 INSN_RS1(insn), 1272 INSN_RS2(insn), 1273 INSN_FUNCT7(insn) >> 2); 1274 db_print_riscv_fpround(", ", INSN_FUNCT3(insn)); 1275 db_printf("\n"); 1276 break; 1277 case FMT_I: 1278 /* immediates */ 1279 imm = INSN_IMM_I(insn); 1280 1281 table = d->u.entries.v; 1282 numtable = d->u.entries.n; 1283 info = riscv_disasm_match(table, numtable, insn, imm); 1284 if (info == NULL) { 1285 return EINVAL; 1286 } 1287 1288 if (info->matchflags & SHIFT32) { 1289 imm &= 31; 1290 } else if (info->matchflags & SHIFT64) { 1291 imm &= 63; 1292 } 1293 1294 /* name */ 1295 db_print_riscv_insnname(insn, info); 1296 1297 /* rd */ 1298 if ((info->matchflags & RD_0) == 0) { 1299 db_printf("%s", sep); 1300 db_print_riscv_reg(INSN_RD(insn), 1301 info->printflags & RD_FREG); 1302 sep = ", "; 1303 } 1304 1305 if (info->printflags & MEMORYIMM) { 1306 db_printf("%s", sep); 1307 db_printf("%d(", (int32_t)imm); 1308 db_print_riscv_reg(INSN_RS1(insn), 1309 info->printflags & RS1_FREG); 1310 db_printf(")"); 1311 } 1312 else { 1313 /* rs1 */ 1314 if ((info->matchflags & RS1_0) == 0) { 1315 db_printf("%s", sep); 1316 db_print_riscv_reg(INSN_RS1(insn), 1317 info->printflags & RS1_FREG); 1318 sep = ", "; 1319 } 1320 1321 /* imm */ 1322 if (info->matchflags & IMM_0) { 1323 /* nothing */ 1324 } else if (info->printflags & FENCEIMM) { 1325 unsigned pred, succ; 1326 1327 /* fm is part of the name, doesn't go here */ 1328 pred = (imm >> 4) & 0xf; 1329 succ = imm & 0xf; 1330 db_printf("%s", sep); 1331 db_print_riscv_fencebits(pred); 1332 db_printf(", "); 1333 db_print_riscv_fencebits(succ); 1334 } else if (info->printflags & BRANCHIMM) { 1335 /* should be B format and not come here */ 1336 } else if (info->printflags & DECIMM) { 1337 db_printf("%s%d", sep, (int32_t)imm); 1338 } else { 1339 db_printf("%s0x%x", sep, imm); 1340 } 1341 } 1342 db_printf("\n"); 1343 break; 1344 case FMT_In: 1345 /* same as I but funct3 should be 0 so just one case */ 1346 if (INSN_FUNCT3(insn) != 0) { 1347 return EINVAL; 1348 } 1349 db_printf("%s %s, %s, 0x%x\n", 1350 d->u.name, 1351 riscv_registers[INSN_RD(insn)], 1352 riscv_registers[INSN_RS1(insn)], 1353 INSN_IMM_I(insn)); 1354 break; 1355 case FMT_S: 1356 /* stores */ 1357 imm = INSN_IMM_S(insn); 1358 1359 table = d->u.entries.v; 1360 numtable = d->u.entries.n; 1361 info = riscv_disasm_match(table, numtable, insn, imm); 1362 if (info == NULL) { 1363 return EINVAL; 1364 } 1365 1366 /* name */ 1367 db_print_riscv_insnname(insn, info); 1368 db_printf(" "); 1369 1370 db_print_riscv_reg(INSN_RS2(insn), 1371 info->printflags & RS2_FREG); 1372 db_printf("%s", sep); 1373 1374 db_printf("%d(", (int32_t)imm); 1375 db_print_riscv_reg(INSN_RS1(insn), 1376 info->printflags & RS1_FREG); 1377 db_printf(")\n"); 1378 break; 1379 case FMT_B: 1380 /* branches */ 1381 imm = INSN_IMM_B(insn); 1382 1383 table = d->u.entries.v; 1384 numtable = d->u.entries.n; 1385 info = riscv_disasm_match(table, numtable, insn, imm); 1386 if (info == NULL) { 1387 return EINVAL; 1388 } 1389 1390 /* name */ 1391 db_print_riscv_insnname(insn, info); 1392 db_printf(" "); 1393 1394 db_print_riscv_reg(INSN_RS1(insn), 1395 info->printflags & RS1_FREG); 1396 db_printf(", "); 1397 1398 db_print_riscv_reg(INSN_RS2(insn), 1399 info->printflags & RS2_FREG); 1400 db_printf(", "); 1401 db_print_addr(loc + (int32_t)imm); 1402 db_printf("\n"); 1403 break; 1404 case FMT_U: 1405 /* large immediates */ 1406 db_printf("%s %s, 0x%x\n", 1407 d->u.name, 1408 riscv_registers[INSN_RD(insn)], 1409 INSN_IMM_U(insn)); 1410 break; 1411 case FMT_J: 1412 /* jal */ 1413 db_printf("%s %s, ", 1414 d->u.name, 1415 riscv_registers[INSN_RD(insn)]); 1416 db_print_addr(loc + (int32_t)INSN_IMM_J(insn)); 1417 db_printf("\n"); 1418 break; 1419 case FMT_UNKNOWN: 1420 /* reserved, custom, etc. */ 1421 return EINVAL; 1422 case FMT_ASSERT: 1423 /* shouldn't have come here */ 1424 return EINVAL; 1425 } 1426 return 0; 1427 } 1428 1429 //////////////////////////////////////////////////////////// 1430 1431 static void 1432 db_disasm_unknown(const uint16_t *insn, unsigned n) 1433 { 1434 unsigned i; 1435 1436 db_printf(".insn%u 0x", n*16); 1437 for (i=n; i-- > 0; ) { 1438 db_printf("%02x", insn[i]); 1439 } 1440 db_printf("\n"); 1441 } 1442 1443 db_addr_t 1444 db_disasm(db_addr_t loc, bool altfmt) 1445 { 1446 /* instructions are up to 5 halfwords */ 1447 uint16_t insn[5]; 1448 unsigned n, i; 1449 uint32_t insn32; 1450 1451 /* 1452 * Fetch the instruction. The first halfword tells us how many 1453 * more there are, and they're always in little-endian order. 1454 */ 1455 db_read_bytes(loc, sizeof(insn[0]), (void *)&insn[0]); 1456 n = INSN_HALFWORDS(insn[0]); 1457 for (i = 1; i < n; i++) { 1458 db_read_bytes(loc + i * sizeof(insn[i]), sizeof(insn[i]), 1459 (void *)&insn[i]); 1460 } 1461 1462 switch (n) { 1463 case 1: 1464 if (db_disasm_16(loc, insn[0], altfmt) != 0) { 1465 db_disasm_unknown(insn, n); 1466 } 1467 break; 1468 case 2: 1469 insn32 = ((uint32_t)insn[1] << 16) | insn[0]; 1470 if (db_disasm_32(loc, insn32, altfmt) != 0) { 1471 db_disasm_unknown(insn, n); 1472 } 1473 break; 1474 default: 1475 /* no standard instructions of size 3+ */ 1476 db_disasm_unknown(insn, n); 1477 break; 1478 } 1479 return loc + n * sizeof(uint16_t); 1480 } 1481