summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Miller <miller.research@gmail.com>2020-11-09 11:33:44 +0000
committerRichard Miller <miller.research@gmail.com>2020-11-09 11:33:44 +0000
commit2a571cc0ece4073eb56d5ccfc3e061a09a353e13 (patch)
tree7daccd0dac9144a55a00570e3fb11af7f0862659
parented97654bd7a11d480b44505c8300d06b42e5fefe (diff)
Add riscv and riscv64 support to libmach
-rw-r--r--utils/include/a.out.h4
-rw-r--r--utils/include/mach.h12
-rw-r--r--utils/libmach/elf.h1
-rw-r--r--utils/libmach/executable.c30
-rw-r--r--utils/libmach/i.c70
-rw-r--r--utils/libmach/idb.c697
-rw-r--r--utils/libmach/iobj.c134
-rw-r--r--utils/libmach/j.c70
-rw-r--r--utils/libmach/mkfile4
-rw-r--r--utils/libmach/obj.c6
-rw-r--r--utils/libmach/setmach.c16
-rw-r--r--utils/libmach/uregi.h57
-rw-r--r--utils/libmach/uregj.h39
13 files changed, 1136 insertions, 4 deletions
diff --git a/utils/include/a.out.h b/utils/include/a.out.h
index 86c7d061..915cdaae 100644
--- a/utils/include/a.out.h
+++ b/utils/include/a.out.h
@@ -31,9 +31,11 @@ struct Exec
#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
#define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */
#define R_MAGIC _MAGIC(HDR_MAGIC, 28) /* arm64 */
+#define Z_MAGIC _MAGIC(0, 29) /* riscv */
+#define Y_MAGIC _MAGIC(0, 30) /* riscv64 */
#define MIN_MAGIC 8
-#define MAX_MAGIC 28 /* <= 90 */
+#define MAX_MAGIC 30 /* <= 90 */
#define DYN_MAGIC 0x80000000 /* dlm */
diff --git a/utils/include/mach.h b/utils/include/mach.h
index 1c8d7a83..25e89279 100644
--- a/utils/include/mach.h
+++ b/utils/include/mach.h
@@ -16,6 +16,8 @@
* powerpc,
* powerpc64
* arm64
+ * riscv
+ * riscv64
*/
enum
{
@@ -36,6 +38,8 @@ enum
MAMD64,
MPOWER64,
MARM64,
+ MRISCV,
+ MRISCV64,
/* types of executables */
FNONE = 0, /* unidentified */
FMIPS, /* v.out */
@@ -67,6 +71,10 @@ enum
FPOWER64B, /* 9.out bootable */
FARM64, /* arm64 */
FARM64B, /* arm64 bootable */
+ FRISCV, /* riscv */
+ FRISCVB, /* riscv bootable */
+ FRISCV64, /* riscv64 */
+ FRISCV64B, /* riscv64 bootable */
ANONE = 0, /* dissembler types */
AMIPS,
@@ -85,6 +93,8 @@ enum
AAMD64,
APOWER64,
AARM64,
+ ARISCV,
+ ARISCV64,
/* object file types */
Obj68020 = 0, /* .2 */
ObjSparc, /* .k */
@@ -103,6 +113,8 @@ enum
ObjSpim, /* .0 */
ObjPower64, /* .9 */
ObjArm64, /* .4? */
+ ObjRiscv, /* .i */
+ ObjRiscv64, /* .j */
Maxobjtype,
CNONE = 0, /* symbol table classes */
diff --git a/utils/libmach/elf.h b/utils/libmach/elf.h
index 6bd483d2..e945ba11 100644
--- a/utils/libmach/elf.h
+++ b/utils/libmach/elf.h
@@ -84,6 +84,7 @@ enum {
ARM = 40, /* ARM */
AMD64 = 62, /* Amd64 */
ARM64 = 183, /* ARM64 */
+ RISCV = 243, /* RISC-V */
NO_VERSION = 0, /* version, ident[VERSION] */
CURRENT = 1,
diff --git a/utils/libmach/executable.c b/utils/libmach/executable.c
index b9954f0a..2734cf44 100644
--- a/utils/libmach/executable.c
+++ b/utils/libmach/executable.c
@@ -65,6 +65,8 @@ extern Mach mamd64;
extern Mach marm;
extern Mach mpower;
extern Mach mpower64;
+extern Mach mriscv;
+extern Mach mriscv64;
ExecTable exectab[] =
{
@@ -203,6 +205,24 @@ ExecTable exectab[] =
sizeof(Exec),
leswal,
armdotout },
+ { Z_MAGIC, /* riscv i.out */
+ "riscv executable",
+ nil,
+ FRISCV,
+ 0,
+ &mriscv,
+ sizeof(Exec),
+ beswal,
+ common },
+ { Y_MAGIC, /* riscv j.out */
+ "riscv64 executable",
+ nil,
+ FRISCV64,
+ 0,
+ &mriscv64,
+ sizeof(Exec),
+ beswal,
+ common },
{ 0 },
};
@@ -357,6 +377,12 @@ commonboot(Fhdr *fp)
fp->name = "amd64 plan 9 boot image";
fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
break;
+ case FRISCV:
+ fp->type = FRISCVB;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "riscv plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ break;
default:
return;
}
@@ -580,6 +606,10 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
mach = &marm;
fp->type = FARM;
break;
+ case RISCV:
+ mach = &mriscv;
+ fp->type = FRISCV;
+ break;
default:
return 0;
}
diff --git a/utils/libmach/i.c b/utils/libmach/i.c
new file mode 100644
index 00000000..659ca3c3
--- /dev/null
+++ b/utils/libmach/i.c
@@ -0,0 +1,70 @@
+/*
+ * RISC-V definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "uregi.h"
+#include <mach.h>
+
+#define REGOFF(x) offsetof(struct Ureg, x)
+#define REGSIZE sizeof(struct Ureg)
+
+Reglist riscvreglist[] = {
+ {"PC", REGOFF(pc), RINT, 'X'},
+ {"SP", REGOFF(r27), RINT, 'X'},
+ {"R31", REGOFF(r31), RINT, 'X'},
+ {"R30", REGOFF(r30), RINT, 'X'},
+ {"R28", REGOFF(r28), RINT, 'X'},
+ {"R27", REGOFF(r27), RINT, 'X'},
+ {"R26", REGOFF(r26), RINT, 'X'},
+ {"R25", REGOFF(r25), RINT, 'X'},
+ {"R24", REGOFF(r24), RINT, 'X'},
+ {"R23", REGOFF(r23), RINT, 'X'},
+ {"R22", REGOFF(r22), RINT, 'X'},
+ {"R21", REGOFF(r21), RINT, 'X'},
+ {"R20", REGOFF(r20), RINT, 'X'},
+ {"R19", REGOFF(r19), RINT, 'X'},
+ {"R18", REGOFF(r18), RINT, 'X'},
+ {"R17", REGOFF(r17), RINT, 'X'},
+ {"R16", REGOFF(r16), RINT, 'X'},
+ {"R15", REGOFF(r15), RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R1", REGOFF(r1), RINT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach mriscv =
+{
+ "riscv",
+ MRISCV, /* machine type */
+ riscvreglist, /* register set */
+ REGSIZE, /* register set size */
+ 0, /* fp register set size */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R1", /* name of link register */
+ "setSB", /* static base register name */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0x80000000ULL, /* kernel base */
+ 0xC0000000ULL, /* kernel text mask */
+ 0x3FFFFFFFULL, /* user stack top */
+ 2, /* quantization of pc */
+ 4, /* szaddr */
+ 4, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/idb.c b/utils/libmach/idb.c
new file mode 100644
index 00000000..62df623e
--- /dev/null
+++ b/utils/libmach/idb.c
@@ -0,0 +1,697 @@
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+#include "ic/i.out.h"
+
+static char *riscvexcep(Map*, Rgetter);
+
+/*
+ * RISCV-specific debugger interface
+ */
+
+typedef struct Instr Instr;
+struct Instr
+{
+ Map *map;
+ ulong w;
+ uvlong addr;
+ char *fmt;
+ int n;
+ int op;
+ int func3;
+ int func7;
+ char rs1, rs2, rs3, rd;
+ char rv64;
+ long imm;
+
+ char* curr; /* fill point in buffer */
+ char* end; /* end of buffer */
+};
+
+typedef struct Optab Optab;
+struct Optab {
+ int func7;
+ int op[8];
+};
+
+typedef struct Opclass Opclass;
+struct Opclass {
+ char *fmt;
+ Optab tab[4];
+};
+
+/* Major opcodes */
+enum {
+ OLOAD, OLOAD_FP, Ocustom_0, OMISC_MEM, OOP_IMM, OAUIPC, OOP_IMM_32, O48b,
+ OSTORE, OSTORE_FP, Ocustom_1, OAMO, OOP, OLUI, OOP_32, O64b,
+ OMADD, OMSUB, ONMSUB, ONMADD, OOP_FP, Ores_0, Ocustom_2, O48b_2,
+ OBRANCH, OJALR, Ores_1, OJAL, OSYSTEM, Ores_2, Ocustom_3, O80b
+};
+
+/* copy anames from compiler */
+static
+#include "ic/enam.c"
+
+static Opclass opOLOAD = {
+ "a,d",
+ 0, AMOVB, AMOVH, AMOVW, AMOV, AMOVBU, AMOVHU, AMOVWU, 0,
+};
+static Opclass opOLOAD_FP = {
+ "a,fd",
+ 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0,
+};
+static Opclass opOMISC_MEM = {
+ "",
+ 0, AFENCE, AFENCE_I,0, 0, 0, 0, 0, 0,
+};
+static Opclass opOOP_IMM = {
+ "$i,s,d",
+ 0x20, 0, 0, 0, 0, 0, ASRA, 0, 0,
+ 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND,
+};
+static Opclass opOAUIPC = {
+ "$i(PC),d",
+ 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI,
+};
+static Opclass opOOP_IMM_32 = {
+ "$i,s,d",
+ 0x20, 0, 0, 0, 0, 0, ASRAW, 0, 0,
+ 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0,
+};
+static Opclass opOSTORE = {
+ "2,a",
+ 0, AMOVB, AMOVH, AMOVW, AMOV, 0, 0, 0, 0,
+};
+static Opclass opOSTORE_FP = {
+ "f2,a",
+ 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0,
+};
+static Opclass opOAMO = {
+ "7,2,s,d",
+ 0x04, 0, 0, ASWAP_W,ASWAP_D,0, 0, 0, 0,
+ 0x08, 0, 0, ALR_W, ALR_D, 0, 0, 0, 0,
+ 0x0C, 0, 0, ASC_W, ASC_D, 0, 0, 0, 0,
+ 0, 0, 0, AAMO_W, AAMO_D, 0, 0, 0, 0,
+};
+static Opclass opOOP = {
+ "2,s,d",
+ 0x01, AMUL, AMULH, AMULHSU,AMULHU, ADIV, ADIVU, AREM, AREMU,
+ 0x20, ASUB, 0, 0, 0, 0, ASRA, 0, 0,
+ 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND,
+};
+static Opclass opOLUI = {
+ "$i,d",
+ 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI,
+};
+static Opclass opOOP_32 = {
+ "2,s,d",
+ 0x01, AMULW, 0, 0, 0, ADIVW, ADIVUW, AREMW, AREMUW,
+ 0x20, ASUBW, 0, 0, 0, 0, ASRAW, 0, 0,
+ 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0,
+};
+static Opclass opOBRANCH = {
+ "2,s,p",
+ 0, ABEQ, ABNE, 0, 0, ABLT, ABGE, ABLTU, ABGEU,
+};
+static Opclass opOJALR = {
+ "d,a",
+ 0, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR,
+};
+static Opclass opOJAL = {
+ "d,p",
+ 0, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL,
+};
+static Opclass opOSYSTEM = {
+ "",
+ 0, ASYS, ACSRRW, ACSRRS, ACSRRC, 0, ACSRRWI,ACSRRSI,ACSRRCI,
+};
+static char fmtcsr[] = "c,s,d";
+static char fmtcsri[] = "c,js,d";
+static char *fmtOSYSTEM[8] = {
+ "$i", fmtcsr, fmtcsr, fmtcsr, "", fmtcsri, fmtcsri, fmtcsri,
+};
+static Opclass opOOP_FP = {
+ "fs,fd",
+ 0x0, AADDF, ASUBF, AMULF, ADIVF, AMOVF, 0, 0, 0,
+ 0x1, AMOVDF, 0, 0, 0, 0, 0, 0, 0,
+ 0x2, ACMPLEF,ACMPLTF,ACMPEQF,0, 0, 0, 0, 0,
+ 0x3, AMOVFW, 0, AMOVFV, 0, AMOVWF, AMOVUF, AMOVVF, AMOVUVF,
+};
+static Opclass opOOP_DP = {
+ "f2,fs,fd",
+ 0x0, AADDD, ASUBD, AMULD, ADIVD, AMOVD, 0, 0, 0,
+ 0x1, AMOVFD, 0, 0, 0, 0, 0, 0, 0,
+ 0x2, ACMPLED,ACMPLTD,ACMPEQD,0, 0, 0, 0, 0,
+ 0x3, AMOVDW, 0, AMOVDV, 0, AMOVWD, AMOVUD, AMOVVD, AMOVUVD,
+};
+
+typedef struct Compclass Compclass;
+struct Compclass {
+ char *fmt;
+ uchar immbits[18];
+};
+
+static Compclass rv32compressed[0x2D] = {
+/* 00-07 ([1:0] = 0) ([15:13] = 0-7) */
+ {"ADDI4SPN $i,d", 22, 6, 5, 11, 12, 7, 8, 9, 10}, /* 12:5 → 5:4|9:6|2|3 */
+ {"FLD a,fd", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
+ {"LW a,d", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */
+ {"FLW a,fd", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */
+ {"? ", 0},
+ {"FSD f2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
+ {"SW 2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */
+ {"FSW f2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */
+
+/* 08-0F ([1:0] = 1) ([15:13] = 0-7 not 4) */
+ {"ADDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
+ {"JAL p", ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 rv32 D*/
+ {"LI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
+ {"LUI $i,d", ~14, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 17:12 */
+ {"? ", 0},
+ {"J p", ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 */
+ {"BEQZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */
+ {"BNEZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */
+
+/* 10-17 ([1:0] = 2) ([15:13] = 0-7 not 4) */
+ {"SLLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */
+ {"FLDSP i,fd", 23, 5, 6, 12, 2, 3, 4}, /* 12|6:2 → 5:3|8:6 */
+ {"LWSP i,d", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 */
+ {"FLWSP i,fd", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 rv32 */
+ {"? ", 0},
+ {"FSDSP f2,$i", 23, 10, 11, 12, 7, 8, 9}, /* 12:7 → 5:3|8:6 */
+ {"SWSP 2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 */
+ {"FSWSP f2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 rv32 */
+
+/* 18-1A ([1:0] = 1) ([15:13] = 4) ([11:10] = 0-2) */
+ {"SRLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */
+ {"SRAI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */
+ {"ANDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
+
+/* 1B-22 ([1:0] = 1) ([15:13] = 4) ([11:10] = 3) ([12] = 0-1) ([6:5] = 0-3) */
+ {"SUB 2,d", 0},
+ {"XOR 2,d", 0},
+ {"OR 2,d", 0},
+ {"AND 2,d", 0},
+ {"SUBW 2,d", 0}, /* rv64 */
+ {"ADDW 2,d", 0}, /* rv64 */
+ {"? ", 0},
+ {"? ", 0},
+
+/* 23-26 ([1:0] = 2) ([15:13] = 4) ((rs2 != 0) = 0-1) */
+ {"JR s", 0},
+ {"MV 2,d", 0},
+ {"JALR s", 0},
+ {"ADD 2,d", 0},
+
+/* 27-27 ([1:0] = 1) ([15:13] = 3) ( rd = 2) */
+ {"ADDI16SP $i", ~22, 6, 2, 5, 3, 4, 12}, /* 12|6:2 → * 9|4|6|8:7|5 */
+
+/* 28-2C rv64 alternates */
+ {"LD a,d", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
+ {"SD 2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
+ {"ADDIW $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
+ {"LDSP i,d", 23, 5, 6, 12, 2, 3, }, /* 12|6:2 → 5:3|8:6 */
+ {"SDSP 2,i", 23, 10, 11, 12, 7, 8, 9} /* 12:7 → 5:3|8:6 */
+};
+
+/* map major opcodes to opclass table */
+static Opclass *opclass[32] = {
+ [OLOAD] &opOLOAD,
+ [OLOAD_FP] &opOLOAD_FP,
+ [OMISC_MEM] &opOMISC_MEM,
+ [OOP_IMM] &opOOP_IMM,
+ [OAUIPC] &opOAUIPC,
+ [OOP_IMM_32] &opOOP_IMM_32,
+ [OSTORE] &opOSTORE,
+ [OSTORE_FP] &opOSTORE_FP,
+ [OAMO] &opOAMO,
+ [OOP] &opOOP,
+ [OLUI] &opOLUI,
+ [OOP_FP] &opOOP_FP,
+ [OOP_32] &opOOP_32,
+ [OBRANCH] &opOBRANCH,
+ [OJALR] &opOJALR,
+ [OJAL] &opOJAL,
+ [OSYSTEM] &opOSYSTEM,
+};
+
+/*
+ * Print value v as name[+offset]
+ */
+static int
+gsymoff(char *buf, int n, ulong v, int space)
+{
+ Symbol s;
+ int r;
+ long delta;
+
+ r = delta = 0; /* to shut compiler up */
+ if (v) {
+ r = findsym(v, space, &s);
+ if (r)
+ delta = v-s.value;
+ if (delta < 0)
+ delta = -delta;
+ }
+ if (v == 0 || r == 0 || delta >= 4096)
+ return snprint(buf, n, "#%lux", v);
+ if (strcmp(s.name, ".string") == 0)
+ return snprint(buf, n, "#%lux", v);
+ if (!delta)
+ return snprint(buf, n, "%s", s.name);
+ if (s.type != 't' && s.type != 'T')
+ return snprint(buf, n, "%s+%llux", s.name, v-s.value);
+ else
+ return snprint(buf, n, "#%lux", v);
+}
+
+#pragma varargck argpos bprint 2
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+format(Instr *i, char *opcode, char *f)
+{
+ int c;
+ long imm;
+ char reg;
+
+ reg = 'R';
+ if(opcode != nil){
+ bprint(i, "%s", opcode);
+ if(f == 0)
+ return;
+ bprint(i, "\t");
+ }else
+ bprint(i, "C.");
+ for(; (c = *f); f++){
+ switch(c){
+ default:
+ bprint(i, "%c", c);
+ break;
+ case ' ':
+ bprint(i, "\t");
+ break;
+ case 'f':
+ reg = 'F';
+ break;
+ case 'j':
+ reg = '$';
+ break;
+ case 's':
+ bprint(i, "%c%d", reg, i->rs1);
+ reg = 'R';
+ break;
+ case '2':
+ bprint(i, "%c%d", reg, i->rs2);
+ reg = 'R';
+ break;
+ case '3':
+ bprint(i, "%c%d", reg, i->rs3);
+ break;
+ case 'd':
+ bprint(i, "%c%d", reg, i->rd);
+ reg = 'R';
+ break;
+ case 'i':
+ imm = i->imm;
+ if(imm < 0)
+ bprint(i, "-%lux", -imm);
+ else
+ bprint(i, "%lux", imm);
+ break;
+ case 'p':
+ imm = i->addr + i->imm;
+ i->curr += gsymoff(i->curr, i->end-i->curr, imm, CANY);
+ break;
+ case 'a':
+ if(i->rs1 == REGSB && mach->sb){
+ i->curr += gsymoff(i->curr, i->end-i->curr, i->imm+mach->sb, CANY);
+ bprint(i, "(SB)");
+ break;
+ }
+ bprint(i, "%lx(R%d)", i->imm, i->rs1);
+ break;
+ case '7':
+ bprint(i, "%ux", i->func7);
+ break;
+ case 'c':
+ bprint(i, "CSR(%lx)", i->imm&0xFFF);
+ break;
+ }
+ }
+}
+
+static int
+badinst(Instr *i)
+{
+ format(i, "???", 0);
+ return 4;
+}
+
+static long
+immshuffle(uint w, uchar *p)
+{
+ int shift, i;
+ ulong imm;
+
+ shift = *p++;
+ imm = 0;
+ while((i = *p++) != 0){
+ imm >>= 1;
+ if((w>>i) & 0x01)
+ imm |= (1<<31);
+ }
+ if(shift & 0x80)
+ imm = (long)imm >> (shift ^ 0xFF);
+ else
+ imm >>= shift;
+ return imm;
+}
+
+static int
+decompress(Instr *i)
+{
+ ushort w;
+ int op, aop;
+ Compclass *cop;
+
+ w = i->w;
+ i->n = 2;
+ i->func3 = (w>>13)&0x7;
+ op = w&0x3;
+ i->op = op;
+ switch(op){
+ case 0:
+ i->rd = 8 + ((w>>2)&0x7);
+ i->rs1 = 8 + ((w>>7)&0x7);
+ i->rs2 = i->rd;
+ break;
+ case 1:
+ i->rd = (w>>7)&0x1F;
+ if((i->func3&0x4) != 0)
+ i->rd = 8 + (i->rd&0x7);
+ i->rs1 = i->rd;
+ i->rs2 = 8 + ((w>>2)&0x7);
+ break;
+ case 2:
+ i->rd = (w>>7)&0x1F;
+ i->rs1 = i->rd;
+ i->rs2 = (w>>2)&0x1F;
+ }
+ aop = (op << 3) + i->func3;
+ if((aop & 0x7) == 4){
+ switch(op){
+ case 1:
+ aop = 0x18 + ((w>>10) & 0x7);
+ if(aop == 0x1B)
+ aop += (w>>5) & 0x3;
+ break;
+ case 2:
+ aop = 0x23 + ((w>>11) & 0x2) + (i->rs2 != 0);
+ break;
+ }
+ }
+ if(aop == 0x0B && i->rd == 2)
+ aop = 0x27;
+ if(i->rv64) switch(aop){
+ case 0x03: aop = 0x28; break;
+ case 0x07: aop = 0x29; break;
+ case 0x09: aop = 0x2A; break;
+ case 0x13: aop = 0x2B; break;
+ case 0x17: aop = 0x2C; break;
+ }
+ cop = &rv32compressed[aop];
+ i->fmt = cop->fmt;
+ i->imm = immshuffle(w, cop->immbits);
+ return 2;
+}
+
+static int
+decode(Map *map, uvlong pc, Instr *i)
+{
+ ulong w;
+ int op;
+
+ if(get4(map, pc, &w) < 0) {
+ werrstr("can't read instruction: %r");
+ return -1;
+ }
+ i->addr = pc;
+ i->map = map;
+ if((w&0x3) != 3){
+ i->w = w & 0xFFFF;
+ return decompress(i);
+ }
+ i->w = w;
+ i->n = 4;
+ op = (w&0x7F);
+ i->op = op;
+ i->func3 = (w>>12)&0x7;
+ i->func7 = (w>>25)&0x7F;
+ i->rs1 = (w>>15)&0x1F;
+ i->rs2 = (w>>20)&0x1F;
+ i->rs3 = (w>>27)&0x1F;
+ i->rd = (w>>7)&0x1F;
+#define FIELD(hi,lo,off) (w>>(lo-off))&(((1<<(hi-lo+1))-1)<<off)
+#define LFIELD(hi,lo,off) (w<<(off-lo))&(((1<<(hi-lo+1))-1)<<off)
+#define SFIELD(lo,off) ((long)(w&((~0)<<lo))>>(lo-off))
+ switch(op>>2) {
+ case OSTORE: /* S-type */
+ case OSTORE_FP:
+ i->imm = SFIELD(25,5) | FIELD(11,7,0);
+ break;
+ case OBRANCH: /* B-type */
+ i->imm = SFIELD(31,12) | LFIELD(7,7,11) | FIELD(30,25,5) | FIELD(11,8,1);
+ break;
+ case OOP_IMM: /* I-type */
+ case OOP_IMM_32:
+ if(i->func3 == 1 || i->func3 == 5){ /* special case ASL/ASR */
+ i->imm = FIELD(25,20,0);
+ break;
+ }
+ /* fall through */
+ case OLOAD:
+ case OLOAD_FP:
+ case OMISC_MEM:
+ case OJALR:
+ case OSYSTEM:
+ i->imm = SFIELD(20,0);
+ break;
+ case OAUIPC: /* U-type */
+ case OLUI:
+ i->imm = SFIELD(12,12);
+ break;
+ case OJAL: /* J-type */
+ i->imm = SFIELD(31,20) | FIELD(19,12,12) | FIELD(20,20,11) | FIELD(30,21,1);
+ break;
+ }
+ return 4;
+}
+
+static int
+pseudo(Instr *i, int aop)
+{
+ char *op;
+
+ switch(aop){
+ case AJAL:
+ if(i->rd == 0){
+ format(i, "JMP", "p");
+ return 1;
+ }
+ break;
+ case AJALR:
+ if(i->rd == 0){
+ format(i, "JMP", "a");
+ return 1;
+ }
+ break;
+ case AADD:
+ if((i->op>>2) == OOP_IMM){
+ op = i->rv64 ? "MOV" : "MOVW";
+ if(i->rs1 == 0)
+ format(i, op, "$i,d");
+ else if(i->rs1 == REGSB && mach->sb && i->rd != REGSB)
+ format(i, op, "$a,d");
+ else if(i->imm == 0)
+ format(i, op, "s,d");
+ else break;
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int
+mkinstr(Instr *i)
+{
+ Opclass *oc;
+ Optab *o;
+ char *fmt;
+ int aop;
+
+ if((i->op&0x3) != 0x3){
+ format(i, nil, i->fmt);
+ return 2;
+ }
+ oc = opclass[i->op>>2];
+ if(oc == 0)
+ return badinst(i);
+ fmt = oc->fmt;
+ if(oc == &opOSYSTEM)
+ fmt = fmtOSYSTEM[i->func3];
+ if(oc == &opOOP_FP){
+ if(i->func7 & 1)
+ oc = &opOOP_DP;
+ o = &oc->tab[i->func7>>5];
+ switch(o->func7){
+ case 0:
+ fmt = "f2,fs,fd";
+ /* fall through */
+ default:
+ aop = o->op[(i->func7>>2)&0x7];
+ if((i->func7&~1) == 0x10){
+ if(i->func3 == 0 && i->rs1 == i->rs2)
+ fmt = "fs,fd";
+ else
+ aop = 0;
+ }
+ break;
+ case 2:
+ aop = o->op[i->func3];
+ break;
+ case 3:
+ if(i->func7 & 0x10)
+ return badinst(i);
+ aop = o->op[(i->func7>>1)&0x4 | (i->rs2&0x3)];
+ if(i->func7 & 0x8)
+ fmt = "s,fd";
+ else
+ fmt = "fs,d";
+ break;
+ }
+ if(aop == 0)
+ return badinst(i);
+ format(i, anames[aop], fmt);
+ return 4;
+ }
+ o = oc->tab;
+ while(o->func7 != 0 && (i->func7 != o->func7 || o->op[i->func3] == 0))
+ o++;
+ if((aop = o->op[i->func3]) == 0)
+ return badinst(i);
+ if(pseudo(i, aop))
+ return 4;
+ format(i, anames[aop], fmt);
+ return 4;
+}
+
+static int
+riscvdas(Map *map, uvlong pc, char modifier, char *buf, int n)
+{
+ Instr i;
+
+ USED(modifier);
+ i.rv64 = 0;
+ i.curr = buf;
+ i.end = buf+n;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ return mkinstr(&i);
+}
+
+static int
+riscv64das(Map *map, uvlong pc, char modifier, char *buf, int n)
+{
+ Instr i;
+
+ USED(modifier);
+ i.rv64 = 1;
+ i.curr = buf;
+ i.end = buf+n;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ return mkinstr(&i);
+}
+
+static int
+riscvhexinst(Map *map, uvlong pc, char *buf, int n)
+{
+ Instr i;
+
+ i.curr = buf;
+ i.end = buf+n;
+ if(decode(map, pc, &i) < 0)
+ return -1;
+ if(i.end-i.curr > 2*i.n)
+ i.curr = _hexify(buf, i.w, 2*i.n - 1);
+ *i.curr = 0;
+ return i.n;
+}
+
+static int
+riscvinstlen(Map *map, uvlong pc)
+{
+ Instr i;
+
+ return decode(map, pc, &i);
+}
+
+static char*
+riscvexcep(Map* m, Rgetter r)
+{
+ return "Trap";
+}
+
+/*
+ * Debugger interface
+ */
+Machdata riscvmach =
+{
+ {0x3a, 0xa0, 0x3d, 0x00}, /* break point */
+ 4, /* break point size */
+
+ leswab, /* short to local byte order */
+ leswal, /* long to local byte order */
+ leswav, /* long to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ riscvexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ 0, /* single precision float printer */
+ 0, /* double precisioin float printer */
+ 0, /* following addresses */
+ riscvdas, /* symbolic disassembly */
+ riscvhexinst, /* hex disassembly */
+ riscvinstlen, /* instruction size */
+};
+
+Machdata riscv64mach =
+{
+ {0x3a, 0xa0, 0x3d, 0x00}, /* break point */
+ 4, /* break point size */
+
+ leswab, /* short to local byte order */
+ leswal, /* long to local byte order */
+ leswav, /* long to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ riscvexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ 0, /* single precision float printer */
+ 0, /* double precisioin float printer */
+ 0, /* following addresses */
+ riscv64das, /* symbolic disassembly */
+ riscvhexinst, /* hex disassembly */
+ riscvinstlen, /* instruction size */
+};
diff --git a/utils/libmach/iobj.c b/utils/libmach/iobj.c
new file mode 100644
index 00000000..a789f30e
--- /dev/null
+++ b/utils/libmach/iobj.c
@@ -0,0 +1,134 @@
+/*
+ * iobj.c - identify and parse a riscv object file
+ */
+#include <lib9.h>
+#include <bio.h>
+#include <mach.h>
+#include "ic/i.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_isi(char *s)
+{
+ return s[0] == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+int
+_readi(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ p->sig = 0;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME){
+ Bread(bp, &p->sig, 4);
+ p->sig = leswal(p->sig);
+ }
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 5); /* reg(1), lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp,1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type){
+ default:
+ case D_NONE: case D_REG: case D_FREG:
+ break;
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ case D_CTLREG:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_VCONST:
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
diff --git a/utils/libmach/j.c b/utils/libmach/j.c
new file mode 100644
index 00000000..26c8c4c8
--- /dev/null
+++ b/utils/libmach/j.c
@@ -0,0 +1,70 @@
+/*
+ * RISC-V RV64 definition
+ */
+#include <lib9.h>
+#include <bio.h>
+#include "uregj.h"
+#include <mach.h>
+
+#define REGOFF(x) offsetof(struct Ureg, x)
+#define REGSIZE sizeof(struct Ureg)
+
+Reglist riscv64reglist[] = {
+ {"PC", REGOFF(pc), RINT, 'X'},
+ {"SP", REGOFF(r27), RINT, 'X'},
+ {"R31", REGOFF(r31), RINT, 'X'},
+ {"R30", REGOFF(r30), RINT, 'X'},
+ {"R28", REGOFF(r28), RINT, 'X'},
+ {"R27", REGOFF(r27), RINT, 'X'},
+ {"R26", REGOFF(r26), RINT, 'X'},
+ {"R25", REGOFF(r25), RINT, 'X'},
+ {"R24", REGOFF(r24), RINT, 'X'},
+ {"R23", REGOFF(r23), RINT, 'X'},
+ {"R22", REGOFF(r22), RINT, 'X'},
+ {"R21", REGOFF(r21), RINT, 'X'},
+ {"R20", REGOFF(r20), RINT, 'X'},
+ {"R19", REGOFF(r19), RINT, 'X'},
+ {"R18", REGOFF(r18), RINT, 'X'},
+ {"R17", REGOFF(r17), RINT, 'X'},
+ {"R16", REGOFF(r16), RINT, 'X'},
+ {"R15", REGOFF(r15), RINT, 'X'},
+ {"R14", REGOFF(r14), RINT, 'X'},
+ {"R13", REGOFF(r13), RINT, 'X'},
+ {"R12", REGOFF(r12), RINT, 'X'},
+ {"R11", REGOFF(r11), RINT, 'X'},
+ {"R10", REGOFF(r10), RINT, 'X'},
+ {"R9", REGOFF(r9), RINT, 'X'},
+ {"R8", REGOFF(r8), RINT, 'X'},
+ {"R7", REGOFF(r7), RINT, 'X'},
+ {"R6", REGOFF(r6), RINT, 'X'},
+ {"R5", REGOFF(r5), RINT, 'X'},
+ {"R4", REGOFF(r4), RINT, 'X'},
+ {"R3", REGOFF(r3), RINT, 'X'},
+ {"R2", REGOFF(r2), RINT, 'X'},
+ {"R1", REGOFF(r1), RINT, 'X'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach mriscv64 =
+{
+ "riscv64",
+ MRISCV64, /* machine type */
+ riscv64reglist, /* register set */
+ REGSIZE, /* register set size */
+ 0, /* fp register set size */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R1", /* name of link register */
+ "setSB", /* static base register name */
+ 0, /* static base register value */
+ 0x1000, /* page size */
+ 0x80000000ULL, /* kernel base */
+ 0xC0000000ULL, /* kernel text mask */
+ 0x3FFFFFFFULL, /* user stack top */
+ 2, /* quantization of pc */
+ 8, /* szaddr */
+ 8, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
diff --git a/utils/libmach/mkfile b/utils/libmach/mkfile
index 9114ed66..ac474d15 100644
--- a/utils/libmach/mkfile
+++ b/utils/libmach/mkfile
@@ -7,12 +7,15 @@ OFILES=\
6.$O\
8.$O\
9.$O\
+ i.$O\
+ j.$O\
k.$O\
q.$O\
t.$O\
v.$O\
5db.$O\
8db.$O\
+ idb.$O\
kdb.$O\
qdb.$O\
tdb.$O\
@@ -21,6 +24,7 @@ OFILES=\
6obj.$O\
8obj.$O\
9obj.$O\
+ iobj.$O\
kobj.$O\
qobj.$O\
vobj.$O\
diff --git a/utils/libmach/obj.c b/utils/libmach/obj.c
index 7b1f1b62..5f6e6250 100644
--- a/utils/libmach/obj.c
+++ b/utils/libmach/obj.c
@@ -28,13 +28,15 @@ int _is5(char*),
_isk(char*),
_isq(char*),
_isv(char*),
+ _isi(char*),
_read5(Biobuf*, Prog*),
_read6(Biobuf*, Prog*),
_read8(Biobuf*, Prog*),
_read9(Biobuf*, Prog*),
_readk(Biobuf*, Prog*),
_readq(Biobuf*, Prog*),
- _readv(Biobuf*, Prog*);
+ _readv(Biobuf*, Prog*),
+ _readi(Biobuf*, Prog*);
typedef struct Obj Obj;
typedef struct Symtab Symtab;
@@ -64,6 +66,8 @@ static Obj obj[] =
/*[ObjAmd64]*/ "amd64 .6", _is6, _read6,
/*[ObjSpim]*/ {0, 0,},
/*[ObjPower64]*/ "power64 .9", _is9, _read9,
+ /*[ObjRiscv]*/ "riscv .i", _isi, _readi,
+ /*[ObjRiscv64]*/ "riscv64 .j", _isi, _readi,
/*[Maxobjtype]*/ 0, 0
};
diff --git a/utils/libmach/setmach.c b/utils/libmach/setmach.c
index 7247881c..8bfd3c18 100644
--- a/utils/libmach/setmach.c
+++ b/utils/libmach/setmach.c
@@ -16,9 +16,9 @@ struct machtab
};
extern Mach mmips, msparc, mi386, mamd64,
- marm, mmips2be, mmips2le, mpower, mpower64;
+ marm, mmips2be, mmips2le, mpower, mpower64, mriscv, mriscv64;
extern Machdata mipsmach, sparcmach, i386mach,
- armmach, mipsmach2le, powermach;
+ armmach, mipsmach2le, powermach, riscvmach, riscv64mach;
/*
* machine selection table. machines with native disassemblers should
@@ -99,6 +99,18 @@ Machtab machines[] =
APOWER64,
&mpower64,
&powermach, },
+ { "riscv",
+ FRISCV,
+ FRISCVB,
+ ARISCV,
+ &mriscv,
+ &riscvmach, },
+ { "riscv64",
+ FRISCV64,
+ FRISCV64B,
+ ARISCV64,
+ &mriscv64,
+ &riscv64mach, },
{ 0 }, /*the terminator*/
};
diff --git a/utils/libmach/uregi.h b/utils/libmach/uregi.h
new file mode 100644
index 00000000..27d202b6
--- /dev/null
+++ b/utils/libmach/uregi.h
@@ -0,0 +1,57 @@
+struct Ureg
+{
+ union {
+ uintptr pc;
+ uintptr regs[1];
+ };
+ uintptr r1; /* link */
+ union{
+ uintptr r2;
+ uintptr sp;
+ uintptr usp;
+ };
+ uintptr r3; /* sb */
+ uintptr r4;
+ uintptr r5;
+ uintptr r6; /* up in kernel */
+ uintptr r7; /* m in kernel */
+ union{
+ uintptr r8;
+ uintptr arg;
+ uintptr ret;
+ };
+ uintptr r9;
+ uintptr r10;
+ uintptr r11;
+ uintptr r12;
+ uintptr r13;
+ uintptr r14;
+ uintptr r15;
+ uintptr r16;
+ uintptr r17;
+ uintptr r18;
+ uintptr r19;
+ uintptr r20;
+ uintptr r21;
+ uintptr r22;
+ uintptr r23;
+ uintptr r24;
+ uintptr r25;
+ uintptr r26;
+ uintptr r27;
+ uintptr r28;
+ uintptr r29;
+ uintptr r30;
+ uintptr r31;
+
+ /* csrs: generally supervisor ones */
+ uintptr status;
+ uintptr ie;
+ union {
+ uintptr cause;
+ uintptr type;
+ };
+ uintptr tval; /* faulting address */
+
+ uintptr curmode;
+};
diff --git a/utils/libmach/uregj.h b/utils/libmach/uregj.h
new file mode 100644
index 00000000..593da792
--- /dev/null
+++ b/utils/libmach/uregj.h
@@ -0,0 +1,39 @@
+struct Ureg
+{
+ u64int pc;
+ u64int r1;
+ union{
+ u64int r2;
+ u64int sp;
+ u64int usp;
+ };
+ u64int r3;
+ u64int r4;
+ u64int r5;
+ u64int r6;
+ u64int r7;
+ u64int r8;
+ u64int r9;
+ u64int r10;
+ u64int r11;
+ u64int r12;
+ u64int r13;
+ u64int r14;
+ u64int r15;
+ u64int r16;
+ u64int r17;
+ u64int r18;
+ u64int r19;
+ u64int r20;
+ u64int r21;
+ u64int r22;
+ u64int r23;
+ u64int r24;
+ u64int r25;
+ u64int r26;
+ u64int r27;
+ u64int r28;
+ u64int r29;
+ u64int r30;
+ u64int r31;
+};