1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #include "../cmd/ic/i.out.h"
6
7 static char *riscvexcep(Map*, Rgetter);
8
9 /*
10 * RISCV-specific debugger interface
11 */
12
13 typedef struct Instr Instr;
14 struct Instr
15 {
16 Map *map;
17 ulong w;
18 uvlong addr;
19 char *fmt;
20 int n;
21 int op;
22 int aop;
23 int func3;
24 int func7;
25 char rs1, rs2, rs3, rd;
26 char rv64;
27 long imm;
28
29 char* curr; /* fill point in buffer */
30 char* end; /* end of buffer */
31 };
32
33 typedef struct Optab Optab;
34 struct Optab {
35 int func7;
36 int op[8];
37 };
38
39 typedef struct Opclass Opclass;
40 struct Opclass {
41 char *fmt;
42 Optab tab[4];
43 };
44
45 /* Major opcodes */
46 enum {
47 OLOAD, OLOAD_FP, Ocustom_0, OMISC_MEM, OOP_IMM, OAUIPC, OOP_IMM_32, O48b,
48 OSTORE, OSTORE_FP, Ocustom_1, OAMO, OOP, OLUI, OOP_32, O64b,
49 OMADD, OMSUB, ONMSUB, ONMADD, OOP_FP, Ores_0, Ocustom_2, O48b_2,
50 OBRANCH, OJALR, Ores_1, OJAL, OSYSTEM, Ores_2, Ocustom_3, O80b
51 };
52
53 /* copy anames from compiler */
54 static
55 #include "../cmd/ic/enam.c"
56
57 static Opclass opOLOAD = {
58 "a,d",
59 0, AMOVB, AMOVH, AMOVW, AMOV, AMOVBU, AMOVHU, AMOVWU, 0,
60 };
61 static Opclass opOLOAD_FP = {
62 "a,fd",
63 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0,
64 };
65 static Opclass opOMISC_MEM = {
66 "",
67 0, AFENCE, AFENCE_I,0, 0, 0, 0, 0, 0,
68 };
69 static Opclass opOOP_IMM = {
70 "$i,s,d",
71 0x20, 0, 0, 0, 0, 0, ASRA, 0, 0,
72 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND,
73 };
74 static Opclass opOAUIPC = {
75 "$i(PC),d",
76 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI,
77 };
78 static Opclass opOOP_IMM_32 = {
79 "$i,s,d",
80 0x20, 0, 0, 0, 0, 0, ASRAW, 0, 0,
81 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0,
82 };
83 static Opclass opOSTORE = {
84 "2,a",
85 0, AMOVB, AMOVH, AMOVW, AMOV, 0, 0, 0, 0,
86 };
87 static Opclass opOSTORE_FP = {
88 "f2,a",
89 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0,
90 };
91 static Opclass opOAMO = {
92 "7,2,s,d",
93 0x04, 0, 0, ASWAP_W,ASWAP_D,0, 0, 0, 0,
94 0x08, 0, 0, ALR_W, ALR_D, 0, 0, 0, 0,
95 0x0C, 0, 0, ASC_W, ASC_D, 0, 0, 0, 0,
96 0, 0, 0, AAMO_W, AAMO_D, 0, 0, 0, 0,
97 };
98 static Opclass opOOP = {
99 "2,s,d",
100 0x01, AMUL, AMULH, AMULHSU,AMULHU, ADIV, ADIVU, AREM, AREMU,
101 0x20, ASUB, 0, 0, 0, 0, ASRA, 0, 0,
102 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND,
103 };
104 static Opclass opOLUI = {
105 "$i,d",
106 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI,
107 };
108 static Opclass opOOP_32 = {
109 "2,s,d",
110 0x01, AMULW, 0, 0, 0, ADIVW, ADIVUW, AREMW, AREMUW,
111 0x20, ASUBW, 0, 0, 0, 0, ASRAW, 0, 0,
112 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0,
113 };
114 static Opclass opOBRANCH = {
115 "2,s,p",
116 0, ABEQ, ABNE, 0, 0, ABLT, ABGE, ABLTU, ABGEU,
117 };
118 static Opclass opOJALR = {
119 "d,a",
120 0, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR,
121 };
122 static Opclass opOJAL = {
123 "d,p",
124 0, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL,
125 };
126 static Opclass opOSYSTEM = {
127 "",
128 0, ASYS, ACSRRW, ACSRRS, ACSRRC, 0, ACSRRWI,ACSRRSI,ACSRRCI,
129 };
130 static char fmtcsr[] = "c,s,d";
131 static char fmtcsri[] = "c,js,d";
132 static char *fmtOSYSTEM[8] = {
133 "$i", fmtcsr, fmtcsr, fmtcsr, "", fmtcsri, fmtcsri, fmtcsri,
134 };
135 static Opclass opOOP_FP = {
136 "fs,fd",
137 0x0, AADDF, ASUBF, AMULF, ADIVF, AMOVF, 0, 0, 0,
138 0x1, AMOVDF, 0, 0, 0, 0, 0, 0, 0,
139 0x2, ACMPLEF,ACMPLTF,ACMPEQF,0, 0, 0, 0, 0,
140 0x3, AMOVFW, 0, AMOVFV, 0, AMOVWF, AMOVUF, AMOVVF, AMOVUVF,
141 };
142 static Opclass opOOP_DP = {
143 "f2,fs,fd",
144 0x0, AADDD, ASUBD, AMULD, ADIVD, AMOVD, 0, 0, 0,
145 0x1, AMOVFD, 0, 0, 0, 0, 0, 0, 0,
146 0x2, ACMPLED,ACMPLTD,ACMPEQD,0, 0, 0, 0, 0,
147 0x3, AMOVDW, 0, AMOVDV, 0, AMOVWD, AMOVUD, AMOVVD, AMOVUVD,
148 };
149
150 typedef struct Compclass Compclass;
151 struct Compclass {
152 char *fmt;
153 uchar immbits[18];
154 };
155
156 static Compclass rv32compressed[0x2E] = {
157 /* 00-07 ([1:0] = 0) ([15:13] = 0-7) */
158 {"ADDI4SPN $i,d", 22, 6, 5, 11, 12, 7, 8, 9, 10}, /* 12:5 → 5:4|9:6|2|3 */
159 {"FLD a,fd", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
160 {"LW a,d", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */
161 {"FLW a,fd", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */
162 {"? ", 0},
163 {"FSD f2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
164 {"SW 2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */
165 {"FSW f2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */
166
167 /* 08-0F ([1:0] = 1) ([15:13] = 0-7 not 4) */
168 {"ADDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
169 {"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*/
170 {"LI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
171 {"LUI $i,d", ~14, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 17:12 */
172 {"? ", 0},
173 {"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 */
174 {"BEQZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */
175 {"BNEZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */
176
177 /* 10-17 ([1:0] = 2) ([15:13] = 0-7 not 4) */
178 {"SLLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */
179 {"FLDSP i,fd", 23, 5, 6, 12, 2, 3, 4}, /* 12|6:2 → 5:3|8:6 */
180 {"LWSP i,d", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 */
181 {"FLWSP i,fd", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 rv32 */
182 {"? ", 0},
183 {"FSDSP f2,$i", 23, 10, 11, 12, 7, 8, 9}, /* 12:7 → 5:3|8:6 */
184 {"SWSP 2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 */
185 {"FSWSP f2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 rv32 */
186
187 /* 18-1A ([1:0] = 1) ([15:13] = 4) ([11:10] = 0-2) */
188 {"SRLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */
189 {"SRAI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */
190 {"ANDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
191
192 /* 1B-22 ([1:0] = 1) ([15:13] = 4) ([11:10] = 3) ([12] = 0-1) ([6:5] = 0-3) */
193 {"SUB 2,d", 0},
194 {"XOR 2,d", 0},
195 {"OR 2,d", 0},
196 {"AND 2,d", 0},
197 {"SUBW 2,d", 0}, /* rv64 */
198 {"ADDW 2,d", 0}, /* rv64 */
199 {"? ", 0},
200 {"? ", 0},
201
202 /* 23-26 ([1:0] = 2) ([15:13] = 4) ([12] = 0-1) ((rs2 != 0) = 0-1) */
203 {"JR s", 0},
204 {"MV 2,d", 0},
205 {"JALR s", 0},
206 {"ADD 2,d", 0},
207
208 /* 27-27 ([1:0] = 1) ([15:13] = 3) ( rd = 2) */
209 {"ADDI16SP $i", ~22, 6, 2, 5, 3, 4, 12}, /* 12|6:2 → * 9|4|6|8:7|5 */
210
211 /* 28-2C rv64 alternates */
212 {"LD a,d", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
213 {"SD 2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */
214 {"ADDIW $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */
215 {"LDSP i,d", 23, 5, 6, 12, 2, 3, }, /* 12|6:2 → 5:3|8:6 */
216 {"SDSP 2,i", 23, 10, 11, 12, 7, 8, 9}, /* 12:7 → 5:3|8:6 */
217
218 /* 2D-2D C.ADD with (rd = 0) */
219 {"EBREAK", 0 }
220 };
221
222 /* map major opcodes to opclass table */
223 static Opclass *opclass[32] = {
224 [OLOAD] &opOLOAD,
225 [OLOAD_FP] &opOLOAD_FP,
226 [OMISC_MEM] &opOMISC_MEM,
227 [OOP_IMM] &opOOP_IMM,
228 [OAUIPC] &opOAUIPC,
229 [OOP_IMM_32] &opOOP_IMM_32,
230 [OSTORE] &opOSTORE,
231 [OSTORE_FP] &opOSTORE_FP,
232 [OAMO] &opOAMO,
233 [OOP] &opOOP,
234 [OLUI] &opOLUI,
235 [OOP_FP] &opOOP_FP,
236 [OOP_32] &opOOP_32,
237 [OBRANCH] &opOBRANCH,
238 [OJALR] &opOJALR,
239 [OJAL] &opOJAL,
240 [OSYSTEM] &opOSYSTEM,
241 };
242
243 /*
244 * Print value v as name[+offset]
245 */
246 static int
gsymoff(char * buf,int n,ulong v,int space)247 gsymoff(char *buf, int n, ulong v, int space)
248 {
249 Symbol s;
250 int r;
251 long delta;
252
253 r = delta = 0; /* to shut compiler up */
254 if (v) {
255 r = findsym(v, space, &s);
256 if (r)
257 delta = v-s.value;
258 if (delta < 0)
259 delta = -delta;
260 }
261 if (v == 0 || r == 0 || delta >= 4096)
262 return snprint(buf, n, "#%lux", v);
263 if (strcmp(s.name, ".string") == 0)
264 return snprint(buf, n, "#%lux", v);
265 if (!delta)
266 return snprint(buf, n, "%s", s.name);
267 if (s.type != 't' && s.type != 'T')
268 return snprint(buf, n, "%s+%llux", s.name, v-s.value);
269 else
270 return snprint(buf, n, "#%lux", v);
271 }
272
273 #pragma varargck argpos bprint 2
274
275 static void
bprint(Instr * i,char * fmt,...)276 bprint(Instr *i, char *fmt, ...)
277 {
278 va_list arg;
279
280 va_start(arg, fmt);
281 i->curr = vseprint(i->curr, i->end, fmt, arg);
282 va_end(arg);
283 }
284
285 static void
format(Instr * i,char * opcode,char * f)286 format(Instr *i, char *opcode, char *f)
287 {
288 int c;
289 long imm;
290 char reg;
291
292 reg = 'R';
293 if(opcode != nil){
294 bprint(i, "%s", opcode);
295 if(f == 0)
296 return;
297 bprint(i, "\t");
298 }else
299 bprint(i, "C.");
300 for(; (c = *f); f++){
301 switch(c){
302 default:
303 bprint(i, "%c", c);
304 break;
305 case ' ':
306 bprint(i, "\t");
307 break;
308 case 'f':
309 reg = 'F';
310 break;
311 case 'j':
312 reg = '$';
313 break;
314 case 's':
315 bprint(i, "%c%d", reg, i->rs1);
316 reg = 'R';
317 break;
318 case '2':
319 bprint(i, "%c%d", reg, i->rs2);
320 reg = 'R';
321 break;
322 case '3':
323 bprint(i, "%c%d", reg, i->rs3);
324 break;
325 case 'd':
326 bprint(i, "%c%d", reg, i->rd);
327 reg = 'R';
328 break;
329 case 'i':
330 imm = i->imm;
331 if(imm < 0)
332 bprint(i, "-%lux", -imm);
333 else
334 bprint(i, "%lux", imm);
335 break;
336 case 'p':
337 imm = i->addr + i->imm;
338 i->curr += gsymoff(i->curr, i->end-i->curr, imm, CANY);
339 break;
340 case 'a':
341 if(i->rs1 == REGSB && mach->sb){
342 i->curr += gsymoff(i->curr, i->end-i->curr, i->imm+mach->sb, CANY);
343 bprint(i, "(SB)");
344 break;
345 }
346 bprint(i, "%lx(R%d)", i->imm, i->rs1);
347 break;
348 case '7':
349 bprint(i, "%ux", i->func7);
350 break;
351 case 'c':
352 bprint(i, "CSR(%lx)", i->imm&0xFFF);
353 break;
354 }
355 }
356 }
357
358 static int
badinst(Instr * i)359 badinst(Instr *i)
360 {
361 format(i, "???", 0);
362 return 4;
363 }
364
365 static long
immshuffle(uint w,uchar * p)366 immshuffle(uint w, uchar *p)
367 {
368 int shift, i;
369 ulong imm;
370
371 shift = *p++;
372 imm = 0;
373 while((i = *p++) != 0){
374 imm >>= 1;
375 if((w>>i) & 0x01)
376 imm |= (1<<31);
377 }
378 if(shift & 0x80)
379 imm = (long)imm >> (shift ^ 0xFF);
380 else
381 imm >>= shift;
382 return imm;
383 }
384
385 static int
decompress(Instr * i)386 decompress(Instr *i)
387 {
388 ushort w;
389 int op, aop;
390 Compclass *cop;
391
392 w = i->w;
393 i->n = 2;
394 i->func3 = (w>>13)&0x7;
395 op = w&0x3;
396 i->op = op;
397 switch(op){
398 case 0:
399 i->rd = 8 + ((w>>2)&0x7);
400 i->rs1 = 8 + ((w>>7)&0x7);
401 i->rs2 = i->rd;
402 break;
403 case 1:
404 i->rd = (w>>7)&0x1F;
405 if((i->func3&0x4) != 0)
406 i->rd = 8 + (i->rd&0x7);
407 i->rs1 = i->rd;
408 i->rs2 = 8 + ((w>>2)&0x7);
409 break;
410 case 2:
411 i->rd = (w>>7)&0x1F;
412 i->rs1 = i->rd;
413 i->rs2 = (w>>2)&0x1F;
414 }
415 aop = (op << 3) + i->func3;
416 if((aop & 0x7) == 4){
417 switch(op){
418 case 1:
419 aop = 0x18 + ((w>>10) & 0x3);
420 if(aop == 0x1B)
421 aop += ((w>>10) & 0x4) + ((w>>5) & 0x3);
422 break;
423 case 2:
424 aop = 0x23 + ((w>>11) & 0x2) + (i->rs2 != 0);
425 if(aop == 0x26 && i->rd == 0)
426 aop = 0x2D;
427 break;
428 }
429 }
430 if(aop == 0x0B && i->rd == 2)
431 aop = 0x27;
432 if(i->rv64) switch(aop){
433 case 0x03: aop = 0x28; break;
434 case 0x07: aop = 0x29; break;
435 case 0x09: aop = 0x2A; break;
436 case 0x13: aop = 0x2B; break;
437 case 0x17: aop = 0x2C; break;
438 }
439 i->aop = aop;
440 cop = &rv32compressed[aop];
441 i->fmt = cop->fmt;
442 i->imm = immshuffle(w, cop->immbits);
443 return 2;
444 }
445
446 static int
decode(Map * map,uvlong pc,Instr * i)447 decode(Map *map, uvlong pc, Instr *i)
448 {
449 ulong w;
450 int op;
451
452 if(get4(map, pc, &w) < 0) {
453 werrstr("can't read instruction: %r");
454 return -1;
455 }
456 i->addr = pc;
457 i->map = map;
458 if((w&0x3) != 3){
459 i->w = w & 0xFFFF;
460 return decompress(i);
461 }
462 i->w = w;
463 i->n = 4;
464 op = (w&0x7F);
465 i->op = op;
466 i->func3 = (w>>12)&0x7;
467 i->func7 = (w>>25)&0x7F;
468 i->rs1 = (w>>15)&0x1F;
469 i->rs2 = (w>>20)&0x1F;
470 i->rs3 = (w>>27)&0x1F;
471 i->rd = (w>>7)&0x1F;
472 #define FIELD(hi,lo,off) (w>>(lo-off))&(((1<<(hi-lo+1))-1)<<off)
473 #define LFIELD(hi,lo,off) (w<<(off-lo))&(((1<<(hi-lo+1))-1)<<off)
474 #define SFIELD(lo,off) ((long)(w&((~0)<<lo))>>(lo-off))
475 switch(op>>2) {
476 case OSTORE: /* S-type */
477 case OSTORE_FP:
478 i->imm = SFIELD(25,5) | FIELD(11,7,0);
479 break;
480 case OBRANCH: /* B-type */
481 i->imm = SFIELD(31,12) | LFIELD(7,7,11) | FIELD(30,25,5) | FIELD(11,8,1);
482 break;
483 case OOP_IMM: /* I-type */
484 case OOP_IMM_32:
485 if(i->func3 == 1 || i->func3 == 5){ /* special case ASL/ASR */
486 i->imm = FIELD(25,20,0);
487 break;
488 }
489 /* fall through */
490 case OLOAD:
491 case OLOAD_FP:
492 case OMISC_MEM:
493 case OJALR:
494 case OSYSTEM:
495 i->imm = SFIELD(20,0);
496 break;
497 case OAUIPC: /* U-type */
498 case OLUI:
499 i->imm = SFIELD(12,12);
500 break;
501 case OJAL: /* J-type */
502 i->imm = SFIELD(31,20) | FIELD(19,12,12) | FIELD(20,20,11) | FIELD(30,21,1);
503 break;
504 }
505 return 4;
506 }
507
508 static int
pseudo(Instr * i,int aop)509 pseudo(Instr *i, int aop)
510 {
511 char *op;
512
513 switch(aop){
514 case AJAL:
515 if(i->rd == 0){
516 format(i, "JMP", "p");
517 return 1;
518 }
519 break;
520 case AJALR:
521 if(i->rd == 0){
522 format(i, "JMP", "a");
523 return 1;
524 }
525 break;
526 case AADD:
527 if((i->op>>2) == OOP_IMM){
528 op = i->rv64 ? "MOV" : "MOVW";
529 if(i->rs1 == 0)
530 format(i, op, "$i,d");
531 else if(i->rs1 == REGSB && mach->sb && i->rd != REGSB)
532 format(i, op, "$a,d");
533 else if(i->imm == 0)
534 format(i, op, "s,d");
535 else break;
536 return 1;
537 }
538 break;
539 case ASYS:
540 switch(i->imm){
541 case 0:
542 format(i, "ECALL", nil);
543 return 1;
544 case 1:
545 format(i, "EBREAK", nil);
546 return 1;
547 }
548 }
549 return 0;
550 }
551
552 static int
mkinstr(Instr * i)553 mkinstr(Instr *i)
554 {
555 Opclass *oc;
556 Optab *o;
557 char *fmt;
558 int aop;
559
560 if((i->op&0x3) != 0x3){
561 format(i, nil, i->fmt);
562 return 2;
563 }
564 oc = opclass[i->op>>2];
565 if(oc == 0)
566 return badinst(i);
567 fmt = oc->fmt;
568 if(oc == &opOSYSTEM)
569 fmt = fmtOSYSTEM[i->func3];
570 if(oc == &opOOP_FP){
571 if(i->func7 & 1)
572 oc = &opOOP_DP;
573 o = &oc->tab[i->func7>>5];
574 switch(o->func7){
575 case 0:
576 fmt = "f2,fs,fd";
577 /* fall through */
578 default:
579 aop = o->op[(i->func7>>2)&0x7];
580 if((i->func7&~1) == 0x10){
581 if(i->func3 == 0 && i->rs1 == i->rs2)
582 fmt = "fs,fd";
583 else
584 aop = 0;
585 }
586 break;
587 case 2:
588 aop = o->op[i->func3];
589 break;
590 case 3:
591 if(i->func7 & 0x10)
592 return badinst(i);
593 aop = o->op[(i->func7>>1)&0x4 | (i->rs2&0x3)];
594 if(i->func7 & 0x8)
595 fmt = "s,fd";
596 else
597 fmt = "fs,d";
598 break;
599 }
600 if(aop == 0)
601 return badinst(i);
602 format(i, anames[aop], fmt);
603 return 4;
604 }
605 o = oc->tab;
606 while(o->func7 != 0 && (i->func7 != o->func7 || o->op[i->func3] == 0))
607 o++;
608 if((aop = o->op[i->func3]) == 0)
609 return badinst(i);
610 if(pseudo(i, aop))
611 return 4;
612 format(i, anames[aop], fmt);
613 return 4;
614 }
615
616 static int
riscvdas(Map * map,uvlong pc,char modifier,char * buf,int n)617 riscvdas(Map *map, uvlong pc, char modifier, char *buf, int n)
618 {
619 Instr i;
620
621 USED(modifier);
622 i.rv64 = 0;
623 i.curr = buf;
624 i.end = buf+n;
625 if(decode(map, pc, &i) < 0)
626 return -1;
627 return mkinstr(&i);
628 }
629
630 static int
riscv64das(Map * map,uvlong pc,char modifier,char * buf,int n)631 riscv64das(Map *map, uvlong pc, char modifier, char *buf, int n)
632 {
633 Instr i;
634
635 USED(modifier);
636 i.rv64 = 1;
637 i.curr = buf;
638 i.end = buf+n;
639 if(decode(map, pc, &i) < 0)
640 return -1;
641 return mkinstr(&i);
642 }
643
644 static int
riscvhexinst(Map * map,uvlong pc,char * buf,int n)645 riscvhexinst(Map *map, uvlong pc, char *buf, int n)
646 {
647 Instr i;
648
649 i.curr = buf;
650 i.end = buf+n;
651 if(decode(map, pc, &i) < 0)
652 return -1;
653 if(i.end-i.curr > 2*i.n)
654 i.curr = _hexify(buf, i.w, 2*i.n - 1);
655 *i.curr = 0;
656 return i.n;
657 }
658
659 static int
riscvinstlen(Map * map,uvlong pc)660 riscvinstlen(Map *map, uvlong pc)
661 {
662 Instr i;
663
664 return decode(map, pc, &i);
665 }
666
667 static char*
riscvexcep(Map *,Rgetter)668 riscvexcep(Map*, Rgetter)
669 {
670 return "Trap";
671 }
672
673 static int
riscvfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)674 riscvfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
675 {
676 Instr i;
677 char buf[8];
678 int len;
679
680 len = decode(map, pc, &i);
681 if(len < 0)
682 return -1;
683 foll[0] = pc + len;
684 if(len == 2){
685 switch(i.aop){
686 case 0x0D: /* C.J */
687 case 0x0E: /* C.BEQZ */
688 case 0x0F: /* C.BNEZ */
689 foll[1] = pc + i.imm;
690 return 2;
691 case 0x09: /* C.JAL */
692 foll[0] = pc + i.imm;
693 break;
694 case 0x23: /* C.JR */
695 case 0x25: /* C.JALR */
696 sprint(buf, "R%d", i.rs1);
697 foll[0] = (*rget)(map, buf);
698 break;
699 }
700 return 1;
701 }
702 switch(i.op>>2) {
703 case OBRANCH:
704 foll[1] = pc + i.imm;
705 return 2;
706 case OJAL:
707 foll[0] = pc + i.imm;
708 break;
709 case OJALR:
710 sprint(buf, "R%d", i.rd);
711 foll[0] = (*rget)(map, buf);
712 break;
713 }
714 return 1;
715 }
716
717 /*
718 * Debugger interface
719 */
720 Machdata riscvmach =
721 {
722 {0x02, 0x90}, /* break point */
723 2, /* break point size */
724
725 leswab, /* short to local byte order */
726 leswal, /* long to local byte order */
727 leswav, /* long to local byte order */
728 risctrace, /* C traceback */
729 riscframe, /* Frame finder */
730 riscvexcep, /* print exception */
731 0, /* breakpoint fixup */
732 0, /* single precision float printer */
733 0, /* double precisioin float printer */
734 riscvfoll, /* following addresses */
735 riscvdas, /* symbolic disassembly */
736 riscvhexinst, /* hex disassembly */
737 riscvinstlen, /* instruction size */
738 };
739
740 Machdata riscv64mach =
741 {
742 {0x02, 0x90}, /* break point */
743 2, /* break point size */
744
745 leswab, /* short to local byte order */
746 leswal, /* long to local byte order */
747 leswav, /* long to local byte order */
748 risctrace, /* C traceback */
749 riscframe, /* Frame finder */
750 riscvexcep, /* print exception */
751 0, /* breakpoint fixup */
752 0, /* single precision float printer */
753 0, /* double precisioin float printer */
754 riscvfoll, /* following addresses */
755 riscv64das, /* symbolic disassembly */
756 riscvhexinst, /* hex disassembly */
757 riscvinstlen, /* instruction size */
758 };
759