• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Disassembler for RISC-V.
2    Copyright (C) 2019 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2019.
5 
6    This file is free software; you can redistribute it and/or modify
7    it under the terms of either
8 
9      * the GNU Lesser General Public License as published by the Free
10        Software Foundation; either version 3 of the License, or (at
11        your option) any later version
12 
13    or
14 
15      * the GNU General Public License as published by the Free
16        Software Foundation; either version 2 of the License, or (at
17        your option) any later version
18 
19    or both in parallel, as here.
20 
21    elfutils is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24    General Public License for more details.
25 
26    You should have received copies of the GNU General Public License and
27    the GNU Lesser General Public License along with this program.  If
28    not, see <http://www.gnu.org/licenses/>.  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33 
34 #include <assert.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <inttypes.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "libeblP.h"
43 
44 #define MACHINE_ENCODING LITTLE_ENDIAN
45 #include "memory-access.h"
46 
47 
48 #define ADD_CHAR(ch) \
49   do {									      \
50     if (unlikely (bufcnt == bufsize))					      \
51       goto enomem;							      \
52     buf[bufcnt++] = (ch);						      \
53   } while (0)
54 
55 #define ADD_STRING(str) \
56   do {									      \
57     const char *_str0 = (str);						      \
58     size_t _len0 = strlen (_str0);					      \
59     ADD_NSTRING (_str0, _len0);						      \
60   } while (0)
61 
62 #define ADD_NSTRING(str, len) \
63   do {									      \
64     const char *_str = (str);						      \
65     size_t _len = (len);						      \
66     if (unlikely (bufcnt + _len > bufsize))				      \
67       goto enomem;							      \
68     memcpy (buf + bufcnt, _str, _len);					      \
69     bufcnt += _len;							      \
70   } while (0)
71 
72 
73 static const char *regnames[32] =
74   {
75     "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
76     "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
77     "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
78     "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
79   };
80 #define REG(nr) ((char *) regnames[nr])
81 #define REGP(nr) REG (8 + (nr))
82 
83 
84 static const char *fregnames[32] =
85   {
86     "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
87     "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
88     "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
89     "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
90   };
91 #define FREG(nr) ((char *) fregnames[nr])
92 #define FREGP(nr) FREG (8 + (nr))
93 
94 
95 struct known_csrs
96   {
97     uint16_t nr;
98     const char *name;
99   };
100 
compare_csr(const void * a,const void * b)101 static int compare_csr (const void *a, const void *b)
102 {
103   const struct known_csrs *ka = (const struct known_csrs *) a;
104   const struct known_csrs *kb = (const struct known_csrs *) b;
105   if (ka->nr < kb->nr)
106     return -1;
107   return ka->nr == kb->nr ? 0 : 1;
108 }
109 
110 
111 int
riscv_disasm(Ebl * ebl,const uint8_t ** startp,const uint8_t * end,GElf_Addr addr,const char * fmt,DisasmOutputCB_t outcb,DisasmGetSymCB_t symcb,void * outcbarg,void * symcbarg)112 riscv_disasm (Ebl *ebl,
113 	      const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
114 	      const char *fmt, DisasmOutputCB_t outcb,
115 	      DisasmGetSymCB_t symcb __attribute__((unused)),
116 	      void *outcbarg, void *symcbarg __attribute__((unused)))
117 {
118   const char *const save_fmt = fmt;
119 
120 #define BUFSIZE 512
121   char initbuf[BUFSIZE];
122   size_t bufcnt;
123   size_t bufsize = BUFSIZE;
124   char *buf = initbuf;
125 
126   int retval = 0;
127   while (1)
128     {
129       const uint8_t *data = *startp;
130       assert (data <= end);
131       if (data + 2 > end)
132 	{
133 	  if (data != end)
134 	    retval = -1;
135 	  break;
136 	}
137       uint16_t first = read_2ubyte_unaligned (data);
138 
139       // Determine length.
140       size_t length;
141       if ((first & 0x3) != 0x3)
142 	length = 2;
143       else if ((first & 0x1f) != 0x1f)
144 	length = 4;
145       else if ((first & 0x3f) != 0x3f)
146 	length = 6;
147       else if ((first & 0x7f) != 0x7f)
148 	length = 8;
149       else
150 	{
151 	  uint16_t nnn = (first >> 12) & 0x7;
152 	  if (nnn != 0x7)
153 	    length = 10 + 2 * nnn;
154 	  else
155 	    // This is invalid as of the RISC-V spec on 2019-06-21.
156 	    // The instruction is at least 192 bits in size so use
157 	    // this minimum size.
158 	    length = 24;
159 	}
160       if (data + length > end)
161 	{
162 	  retval = -1;
163 	  break;
164 	}
165 
166       char *mne = NULL;
167       /* Max length is 24, which is "illegal", so we print it as
168          "0x<48 hex chars>"
169          See: No instruction encodings defined for these sizes yet, below  */
170       char mnebuf[50];
171       char *op[5] = { NULL, NULL, NULL, NULL, NULL };
172       char immbuf[32];
173       size_t len;
174       char *strp = NULL;
175       char addrbuf[32];
176       bufcnt = 0;
177       int64_t opaddr;
178       if (length == 2)
179 	{
180 	  size_t idx = (first >> 13) * 3 + (first & 0x3);
181 	  switch (idx)
182 	    {
183 	    uint16_t rd;
184 	    uint16_t rs1;
185 	    uint16_t rs2;
186 
187 	    case 0:
188 	      if ((first & 0x1fe0) != 0)
189 		{
190 		  mne = "addi";
191 		  op[0] = REGP ((first & 0x1c) >> 2);
192 		  op[1] = REG (2);
193 		  opaddr = (((first >> 1) & 0x3c0)
194 			    | ((first >> 7) & 0x30)
195 			    | ((first >> 2) & 0x8)
196 			    | ((first >> 4) & 0x4));
197 		  snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64, opaddr);
198 		  op[2] = addrbuf;
199 		}
200 	      else if (first == 0)
201 		mne = "unimp";
202 	      break;
203 	    case 1:
204 	      rs1 = (first >> 7) & 0x1f;
205 	      int16_t nzimm = ((0 - ((first >> 7) & 0x20))
206 			       | ((first >> 2) & 0x1f));
207 	      if (rs1 == 0)
208 	        mne = nzimm == 0 ? "nop" : "c.nop";
209 	      else
210 		{
211 		  mne = nzimm == 0 ? "c.addi" : "addi";
212 		  op[0] = op[1] = REG (rs1);
213 		  snprintf (addrbuf, sizeof (addrbuf), "%" PRId16, nzimm);
214 		  op[2] = addrbuf;
215 		}
216 	      break;
217 	    case 2:
218 	      rs1 = (first >> 7) & 0x1f;
219 	      op[0] = op[1] = REG (rs1);
220 	      opaddr = ((first >> 7) & 0x20) | ((first >> 2) & 0x1f);
221 	      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr);
222 	      op[2] = addrbuf;
223 	      mne = rs1 == 0 ? "c.slli" : "slli";
224 	      break;
225 	    case 3:
226 	      op[0] = FREGP ((first >> 2) & 0x7);
227 	      opaddr = ((first << 1) & 0xc0) | ((first >> 7) & 0x38);
228 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)",
229 			opaddr, REGP ((first >> 7) & 0x7));
230 	      op[1] = addrbuf;
231 	      mne = "fld";
232 	      break;
233 	    case 4:
234 	      if (ebl->class == ELFCLASS32)
235 		{
236 		  mne = "jal";
237 		  opaddr = (((first << 3) & 0x20) | ((first >> 2) & 0xe)
238 			    | ((first << 1) & 0x80) | ((first >> 1) | 0x40)
239 			    | ((first << 2) & 0x400) | (first & 0xb00)
240 			    | ((first >> 6) & 0x10));
241 		  snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr);
242 		  op[0] = addrbuf;
243 		}
244 	      else
245 		{
246 		  int32_t imm = (((UINT32_C (0) - ((first >> 12) & 0x1)) << 5)
247 				 | ((first >> 2) & 0x1f));
248 		  uint16_t reg = (first >> 7) & 0x1f;
249 		  if (reg == 0)
250 		    {
251 		      // Reserved
252 		      len = snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx16, first);
253 		      strp = addrbuf;
254 		    }
255 		  else
256 		    {
257 		      if (imm == 0)
258 			mne = "sext.w";
259 		      else
260 			{
261 			  mne = "addiw";
262 			  snprintf (addrbuf, sizeof (addrbuf), "%" PRId32, imm);
263 			  op[2] = addrbuf;
264 			}
265 		      op[0] = op[1] = REG (reg);
266 		    }
267 		}
268 	      break;
269 	    case 5:
270 	      op[0] = FREG ((first >> 7) & 0x1f);
271 	      opaddr = ((first << 4) & 0x1c0) | ((first >> 7) & 0x20) | ((first >> 2) & 0x18);
272 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)", opaddr, REG (2));
273 	      op[1] = addrbuf;
274 	      mne = "fld";
275 	      break;
276 	    case 6:
277 	    case 18:
278 	      mne = idx == 6 ? "lw" : "sw";
279 	      op[0] = REGP ((first >> 2) & 0x7);
280 	      opaddr = (((first >> 7) & 0x38) | ((first << 1) & 0x40)
281 			| ((first >> 4) & 0x4));
282 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)",
283 			opaddr, REGP ((first >> 7) & 0x7));
284 	      op[1] = addrbuf;
285 	      break;
286 	    case 7:
287 	      mne = (first & 0xf80) == 0 ? "c.li" : "li";
288 	      op[0] = REG((first >> 7) & 0x1f);
289 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId16,
290 			(UINT16_C (0) - ((first >> 7) & 0x20)) | ((first >> 2) & 0x1f));
291 	      op[1] = addrbuf;
292 	      break;
293 	    case 8:
294 	      rd = ((first >> 7) & 0x1f);
295 	      if (rd == 0)
296 		{
297 		  len = snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx16, first);
298 		  strp = addrbuf;
299 		}
300 	      else
301 		{
302 		  uint16_t uimm = (((first << 4) & 0xc0)
303 				   | ((first >> 7) & 0x20)
304 				   | ((first >> 2) & 0x1c));
305 		  mne = "lw";
306 		  op[0] = REG (rd);
307 		  snprintf (addrbuf, sizeof (addrbuf), "%" PRIu16 "(%s)", uimm, REG (2));
308 		  op[1] = addrbuf;
309 		}
310 	      break;
311 	    case 9:
312 	      if (ebl->class == ELFCLASS32)
313 		{
314 		  mne = "flw";
315 		  op[0] = FREGP ((first >> 2) & 0x7);
316 		  opaddr = (((first << 1) & 0x40)
317 		            | ((first >> 7) & 0x38)
318 			    | ((first >> 4) & 0x4));
319 		}
320 	      else
321 		{
322 		  mne = "ld";
323 		  op[0] = REGP ((first >> 2) & 0x7);
324 		  opaddr = ((first >> 7) & 0x38) | ((first << 1) & 0xc0);
325 		}
326 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)",
327 			opaddr, REGP ((first >> 7) & 0x7));
328 	      op[1] = addrbuf;
329 	      break;
330 	    case 10:
331 	      if ((first & 0xf80) == (2 << 7))
332 		{
333 		  mne = "addi";
334 		  op[0] = op[1] = REG (2);
335 		  opaddr = (((first >> 2) & 0x10) | ((first << 3) & 0x20)
336 			    | ((first << 1) & 0x40) | ((first << 4) & 0x180)
337 			    | ((UINT64_C (0) - ((first >> 12) & 0x1)) << 9));
338 		  snprintf (addrbuf, sizeof (addrbuf), "%" PRId64, opaddr);
339 		  op[2] = addrbuf;
340 		}
341 	      else
342 		{
343 		  mne = "lui";
344 		  op[0] = REG((first & 0xf80) >> 7);
345 		  opaddr = (((UINT64_C (0) - ((first >> 12) & 0x1)) & ~0x1f)
346 			    | ((first >> 2) & 0x1f));
347 		  snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr & 0xfffff);
348 		  op[1] = addrbuf;
349 		}
350 	      break;
351 	    case 11:
352 	      if (ebl->class == ELFCLASS32)
353 		{
354 		  mne = "flw";
355 		  op[0] = FREG ((first >> 7) & 0x1f);
356 		  opaddr = (((first << 4) & 0xc0)
357 			    | ((first >> 7) & 0x20)
358 			    | ((first >> 2) & 0x1c));
359 		}
360 	      else
361 		{
362 		  mne = "ld";
363 		  op[0] = REG ((first >> 7) & 0x1f);
364 		  opaddr = (((first << 4) & 0x1c0)
365 			    | ((first >> 7) & 0x20)
366 			    | ((first >> 2) & 0x18));
367 		}
368 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (2));
369 	      op[1] = addrbuf;
370 	      break;
371 	    case 13:
372 	      if ((first & 0xc00) != 0xc00)
373 		{
374 		  int16_t imm = ((first >> 7) & 0x20) | ((first >> 2) & 0x1f);
375 		  if ((first & 0xc00) == 0x800)
376 		    {
377 		      imm |= 0 - (imm & 0x20);
378 		      mne = "andi";
379 		      snprintf (addrbuf, sizeof (addrbuf), "%" PRId16, imm);
380 		    }
381 		  else
382 		    {
383 		      if (ebl->class != ELFCLASS32 || imm < 32)
384 			{
385 			  mne = (first & 0x400) ? "srai" : "srli";
386 			  if (imm == 0)
387 			    {
388 			      strcpy (stpcpy (mnebuf, "c."), mne);
389 			      mne = mnebuf;
390 			    }
391 			}
392 		      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx16, imm);
393 		    }
394 		  op[2] = addrbuf;
395 		}
396 	      else
397 		{
398 		  op[2] = REGP ((first >> 2) & 0x7);
399 		  static const char *const arithmne[8] =
400 		    {
401 		      "sub", "xor", "or", "and", "subw", "addw", NULL, NULL
402 		    };
403 		  mne = (char *) arithmne[((first >> 10) & 0x4) | ((first >> 5) & 0x3)];
404 		}
405 		op[0] = op[1] = REGP ((first >> 7) & 0x7);
406 	      break;
407 	    case 14:
408 	      rs1 = (first >> 7) & 0x1f;
409 	      rs2 = (first >> 2) & 0x1f;
410 	      op[0] = REG (rs1);
411 	      if ((first & 0x1000) == 0)
412 		{
413 		  if (rs2 == 0)
414 		    {
415 		      op[1] = NULL;
416 		      if (rs1 == 1)
417 			{
418 			  mne = "ret";
419 			  op[0] = NULL;
420 			}
421 		      else
422 			mne = "jr";
423 		    }
424 		  else
425 		    {
426 		      mne = rs1 != 0 ? "mv" : "c.mv";
427 		      op[1] = REG (rs2);
428 		    }
429 		}
430 	      else
431 		{
432 		  if (rs2 == 0)
433 		    {
434 		      if (rs1 == 0)
435 			{
436 			  mne = "ebreak";
437 			  op[0] = op[1] = NULL;
438 			}
439 		      else
440 			mne = "jalr";
441 		    }
442 		  else
443 		    {
444 		      mne = rs1 != 0 ? "add" : "c.add";
445 		      op[2] = REG (rs2);
446 		      op[1] = op[0];
447 		    }
448 		}
449 	      break;
450 	    case 15:
451 	      op[0] = FREGP ((first >> 2) & 0x7);
452 	      opaddr = ((first << 1) & 0xc0) | ((first >> 7) & 0x38);
453 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)",
454 			opaddr, REGP ((first >> 7) & 0x7));
455 	      op[1] = addrbuf;
456 	      mne = "fsd";
457 	      break;
458 	    case 16:
459 	      opaddr = (((UINT64_C (0) - ((first >> 12) & 0x1)) << 11)
460 			| ((first << 2) & 0x400)
461 			| ((first >> 1) & 0x300)
462 			| ((first << 1) & 0x80)
463 			| ((first >> 1) & 0x40)
464 			| ((first << 3) & 0x20)
465 			| ((first >> 7) & 0x10)
466 			| ((first >> 2) & 0xe));
467 	      mne = "j";
468 	      // TODO translate address
469 	      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, addr + opaddr);
470 	      op[0] = addrbuf;
471 	      break;
472 	    case 17:
473 	      op[0] = FREG ((first >> 2) & 0x1f);
474 	      opaddr = ((first >> 1) & 0x1c0) | ((first >> 7) & 0x38);
475 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)", opaddr, REG (2));
476 	      op[1] = addrbuf;
477 	      mne = "fsd";
478 	      break;
479 	    case 19:
480 	    case 22:
481 	      mne = idx == 19 ? "beqz" : "bnez";
482 	      op[0] = REG (8 + ((first >> 7) & 0x7));
483 	      opaddr = addr + (((UINT64_C (0) - ((first >> 12) & 0x1)) & ~0xff)
484 			       | ((first << 1) & 0xc0) | ((first << 3) & 0x20)
485 			       | ((first >> 7) & 0x18) |  ((first >> 2) & 0x6));
486 	      // TODO translate address
487 	      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr);
488 	      op[1] = addrbuf;
489 	      break;
490 	    case 20:
491 	      op[0] = REG ((first >> 2) & 0x1f);
492 	      opaddr = ((first >> 1) & 0xc0) | ((first >> 7) & 0x3c);
493 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (2));
494 	      op[1] = addrbuf;
495 	      mne = "sw";
496 	      break;
497 	    case 21:
498 	      if (idx == 18 || ebl->class == ELFCLASS32)
499 		{
500 		  mne = "fsw";
501 		  op[0] = FREGP ((first >> 2) & 0x7);
502 		  opaddr = (((first >> 7) & 0x38) | ((first << 1) & 0x40)
503 			    | ((first >> 4) & 0x4));
504 		}
505 	      else
506 		{
507 		  mne = "sd";
508 		  op[0] = REGP ((first >> 2) & 0x7);
509 		  opaddr = ((first >> 7) & 0x38) | ((first << 1) & 0xc0);
510 		}
511 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)",
512 			opaddr, REGP ((first >> 7) & 0x7));
513 	      op[1] = addrbuf;
514 	      break;
515 	    case 23:
516 	      if (idx == 18 || ebl->class == ELFCLASS32)
517 		{
518 		  mne = "fsw";
519 		  op[0] = FREG ((first & 0x7c) >> 2);
520 		  opaddr = ((first & 0x1e00) >> 7) | ((first & 0x180) >> 1);
521 		}
522 	      else
523 		{
524 		  mne = "sd";
525 		  op[0] = REG ((first & 0x7c) >> 2);
526 		  opaddr = ((first & 0x1c00) >> 7) | ((first & 0x380) >> 1);
527 		}
528 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (2));
529 	      op[1] = addrbuf;
530 	      break;
531 	    default:
532 	      break;
533 	    }
534 
535 	  if (strp == NULL && mne == NULL)
536 	    {
537 	      len = snprintf (immbuf, sizeof (immbuf), "0x%04" PRIx16, first);
538 	      strp = immbuf;
539 	    }
540 	}
541       else if (length == 4)
542 	{
543 	  uint32_t word = read_4ubyte_unaligned (data);
544 	  size_t idx = (word >> 2) & 0x1f;
545 
546 	  switch (idx)
547 	    {
548 	    static const char widthchar[4] = { 's', 'd', '\0', 'q' };
549 	    static const char intwidthchar[4] = { 'w', 'd', '\0', 'q' };
550 	    static const char *const rndmode[8] = { "rne", "rtz", "rdn", "rup", "rmm", "???", "???", "dyn" };
551 	    uint32_t rd;
552 	    uint32_t rs1;
553 	    uint32_t rs2;
554 	    uint32_t rs3;
555 	    uint32_t func;
556 
557 	    case 0x00:
558 	    case 0x01:
559 	      // LOAD and LOAD-FP
560 	      rd = (word >> 7) & 0x1f;
561 	      op[0] = idx == 0x00 ? REG (rd) : FREG (rd);
562 	      opaddr = ((int32_t) word) >> 20;
563 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)",
564 			opaddr, REG ((word >> 15) & 0x1f));
565 	      op[1] = addrbuf;
566 	      func = (word >> 12) & 0x7;
567 	      static const char *const loadmne[8] =
568 	        {
569 	          "lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", NULL
570 	        };
571 	      static const char *const floadmne[8] =
572 		{
573 		  NULL, NULL, "flw", "fld", "flq", NULL, NULL, NULL
574 		};
575 	      mne = (char *) (idx == 0x00 ? loadmne[func] : floadmne[func]);
576 	      break;
577 	    case 0x03:
578 	      // MISC-MEM
579 	      rd = (word >> 7) & 0x1f;
580 	      rs1 = (word >> 15) & 0x1f;
581 	      func = (word >> 12) & 0x7;
582 
583 	      if (word == 0x8330000f)
584 		mne = "fence.tso";
585 	      else if (word == 0x0000100f)
586 		mne = "fence.i";
587 	      else if (func == 0 && rd == 0 && rs1 == 0 && (word & 0xf0000000) == 0)
588 		{
589 		  static const char *const order[16] =
590 		    {
591 		      "unknown", "w", "r", "rw", "o", "ow", "or", "orw",
592 		      "i", "iw", "ir", "irw", "io", "iow", "ior", "iorw"
593 		    };
594 		  uint32_t pred = (word >> 20) & 0xf;
595 		  uint32_t succ = (word >> 24) & 0xf;
596 		  if (pred != 0xf || succ != 0xf)
597 		    {
598 		      op[0] = (char *) order[succ];
599 		      op[1] = (char *) order[pred];
600 		     }
601 		   mne = "fence";
602 		}
603 	      break;
604 	    case 0x04:
605 	    case 0x06:
606 	      // OP-IMM and OP-IMM32
607 	      rd = (word >> 7) & 0x1f;
608 	      op[0] = REG (rd);
609 	      rs1 = (word >> 15) & 0x1f;
610 	      op[1] = REG (rs1);
611 	      opaddr = ((int32_t) word) >> 20;
612 	      static const char *const opimmmne[8] =
613 		{
614 		  "addi", NULL, "slti", "sltiu", "xori", NULL, "ori", "andi"
615 		};
616 	      func = (word >> 12) & 0x7;
617 	      mne = (char *) opimmmne[func];
618 	      if (mne == NULL)
619 		{
620 		  const uint64_t shiftmask = ebl->class == ELFCLASS32 ? 0x1f : 0x3f;
621 		  if (func == 0x1 && (opaddr & ~shiftmask) == 0)
622 		    mne = "slli";
623 		  else if (func == 0x5 && (opaddr & ~shiftmask) == 0)
624 		    mne = "srli";
625 		  else if (func == 0x5 && (opaddr & ~shiftmask) == 0x400)
626 		    mne = "srai";
627 		  snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr & shiftmask);
628 		  op[2] = addrbuf;
629 		}
630 	      else if (func == 0x0 && (rd != 0 || idx == 0x06) && rs1 == 0 && rd != 0)
631 		{
632 		  mne = "li";
633 		  snprintf (addrbuf, sizeof (addrbuf), "%" PRId64, opaddr);
634 		  op[1] = addrbuf;
635 		}
636 	      else if (func == 0x00 && opaddr == 0)
637 		{
638 		  if (idx == 0x06)
639 		    mne ="sext.";
640 		  else if (rd == 0)
641 		    {
642 		      mne = "nop";
643 		      op[0] = op[1] = NULL;
644 		    }
645 		  else
646 		    mne = "mv";
647 		}
648 	      else if (func == 0x3 && opaddr == 1)
649 		mne = "seqz";
650 	      else if (func == 0x4 && opaddr == -1)
651 		{
652 		  mne = "not";
653 		  op[2] = NULL;
654 		}
655 	      else
656 		{
657 		  snprintf (addrbuf, sizeof (addrbuf), "%" PRId64, opaddr);
658 		  op[2] = addrbuf;
659 
660 		  if (func == 0x0 && rs1 == 0 && rd != 0)
661 		    {
662 		      op[1] = op[2];
663 		      op[2] = NULL;
664 		      mne = "li";
665 		    }
666 		}
667 	      if (mne != NULL && idx == 0x06)
668 		{
669 		  mne = strcpy (mnebuf, mne);
670 		  strcat (mnebuf, "w");
671 		}
672 	      break;
673 	    case 0x05:
674 	    case 0x0d:
675 	      // LUI and AUIPC
676 	      mne = idx == 0x05 ? "auipc" : "lui";
677 	      op[0] = REG ((word >> 7) & 0x1f);
678 	      opaddr = word >> 12;
679 	      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr);
680 	      op[1] = addrbuf;
681 	      break;
682 	    case 0x08:
683 	    case 0x09:
684 	      // STORE and STORE-FP
685 	      rs2 = (word >> 20) & 0x1f;
686 	      op[0] = idx == 0x08 ? REG (rs2) : FREG (rs2);
687 	      opaddr = ((((int64_t) ((int32_t) word) >> 20)) & ~0x1f) | ((word >> 7) & 0x1f);
688 	      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)",
689 			opaddr, REG ((word >> 15) & 0x1f));
690 	      op[1] = addrbuf;
691 	      func = (word >> 12) & 0x7;
692 	      static const char *const storemne[8] =
693 		{
694 		  "sb", "sh", "sw", "sd", NULL, NULL, NULL, NULL
695 		};
696 	      static const char *const fstoremne[8] =
697 		{
698 		  NULL, NULL, "fsw", "fsd", "fsq", NULL, NULL, NULL
699 		};
700 	      mne = (char *) (idx == 0x08 ? storemne[func] : fstoremne[func]);
701 	      break;
702 	    case 0x0b:
703 	      // AMO
704 	      op[0] = REG ((word >> 7) & 0x1f);
705 	      rs1 = (word >> 15) & 0x1f;
706 	      rs2 = (word >> 20) & 0x1f;
707 	      snprintf (addrbuf, sizeof (addrbuf), "(%s)", REG (rs1));
708 	      op[2] = addrbuf;
709 	      size_t width = (word >> 12) & 0x7;
710 	      func = word >> 27;
711 	      static const char *const amomne[32] =
712 		{
713 		  "amoadd", "amoswap", "lr", "sc", "amoxor", NULL, NULL, NULL,
714 		  "amoor", NULL, NULL, NULL, "amoand", NULL, NULL, NULL,
715 		  "amomin", NULL, NULL, NULL, "amomax", NULL, NULL, NULL,
716 		  "amominu", NULL, NULL, NULL, "amomaxu", NULL, NULL, NULL
717 		};
718 	      if (amomne[func] != NULL && width >= 2 && width <= 3
719 		  && (func != 0x02 || rs2 == 0))
720 		{
721 		  if (func == 0x02)
722 		    {
723 		      op[1] = op[2];
724 		      op[2] = NULL;
725 		    }
726 		  else
727 		    op[1] = REG (rs2);
728 
729 		  char *cp = stpcpy (mnebuf, amomne[func]);
730 		  *cp++ = '.';
731 		  *cp++ = "  wd    "[width];
732 		  assert (cp[-1] != ' ');
733 		  static const char *const aqrlstr[4] =
734 		    {
735 		      "", ".rl", ".aq", ".aqrl"
736 		    };
737 		  strcpy (cp, aqrlstr[(word >> 25) & 0x3]);
738 		  mne = mnebuf;
739 		}
740 	      break;
741 	    case 0x0c:
742 	    case 0x0e:
743 	      // OP and OP-32
744 	      if ((word & 0xbc000000) == 0)
745 		{
746 		  rs1 = (word >> 15) & 0x1f;
747 		  rs2 = (word >> 20) & 0x1f;
748 		  op[0] = REG ((word >> 7) & 0x1f);
749 		  func = ((word >> 21) & 0x10) | ((word >> 27) & 0x8) | ((word >> 12) & 0x7);
750 		  static const char *const arithmne2[32] =
751 		    {
752 		      "add", "sll", "slt", "sltu", "xor", "srl", "or", "and",
753 		      "sub", NULL, NULL, NULL, NULL, "sra", NULL, NULL,
754 		      "mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu",
755 		      NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
756 		    };
757 		  static const char *const arithmne3[32] =
758 		    {
759 		      "addw", "sllw", NULL, NULL, NULL, "srlw", NULL, NULL,
760 		      "subw", NULL, NULL, NULL, NULL, "sraw", NULL, NULL,
761 		      "mulw", NULL, NULL, NULL, "divw", "divuw", "remw", "remuw",
762 		      NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
763 		    };
764 		  if (func == 8 && rs1 == 0)
765 		    {
766 		      mne = idx == 0x0c ? "neg" : "negw";
767 		      op[1] = REG (rs2);
768 		    }
769 		  else if (idx == 0x0c && rs2 == 0 && func == 2)
770 		    {
771 		      op[1] = REG (rs1);
772 		      mne = "sltz";
773 		    }
774 		  else if (idx == 0x0c && rs1 == 0 && (func == 2 || func == 3))
775 		    {
776 		      op[1] = REG (rs2);
777 		      mne = func == 2 ? "sgtz" : "snez";
778 		    }
779 		  else
780 		    {
781 		      mne = (char *) (idx == 0x0c ? arithmne2[func] : arithmne3[func]);
782 		      op[1] = REG (rs1);
783 		      op[2] = REG (rs2);
784 		    }
785 		}
786 	      break;
787 	    case 0x10:
788 	    case 0x11:
789 	    case 0x12:
790 	    case 0x13:
791 	      // MADD, MSUB, NMSUB, NMADD
792 	      if ((word & 0x06000000) != 0x04000000)
793 		{
794 		  rd = (word >> 7) & 0x1f;
795 		  rs1 = (word >> 15) & 0x1f;
796 		  rs2 = (word >> 20) & 0x1f;
797 		  rs3 = (word >> 27) & 0x1f;
798 		  uint32_t rm = (word >> 12) & 0x7;
799 		  width = (word >> 25) & 0x3;
800 
801 		  static const char *const fmamne[4] =
802 		    {
803 		      "fmadd.", "fmsub.", "fnmsub.", "fnmadd."
804 		    };
805 		  char *cp = stpcpy (mnebuf, fmamne[idx & 0x3]);
806 		  *cp++ = widthchar[width];
807 		  *cp = '\0';
808 		  mne = mnebuf;
809 		  op[0] = FREG (rd);
810 		  op[1] = FREG (rs1);
811 		  op[2] = FREG (rs2);
812 		  op[3] = FREG (rs3);
813 		  if (rm != 0x7)
814 		    op[4] = (char *) rndmode[rm];
815 		}
816 	      break;
817 	    case 0x14:
818 	      // OP-FP
819 	      if ((word & 0x06000000) != 0x04000000)
820 		{
821 		  width = (word >> 25) & 0x3;
822 		  rd = (word >> 7) & 0x1f;
823 		  rs1 = (word >> 15) & 0x1f;
824 		  rs2 = (word >> 20) & 0x1f;
825 		  func = word >> 27;
826 		  uint32_t rm = (word >> 12) & 0x7;
827 		  if (func < 4)
828 		    {
829 		      static const char *const fpop[4] =
830 			{
831 			  "fadd", "fsub", "fmul", "fdiv"
832 			};
833 		      char *cp = stpcpy (mnebuf, fpop[func]);
834 		      *cp++ = '.';
835 		      *cp++ = widthchar[width];
836 		      *cp = '\0';
837 		      mne = mnebuf;
838 		      op[0] = FREG (rd);
839 		      op[1] = FREG (rs1);
840 		      op[2] = FREG (rs2);
841 		      if (rm != 0x7)
842 			op[3] = (char *) rndmode[rm];
843 		    }
844 		  else if (func == 0x1c && width != 2 && rs2 == 0 && rm <= 1)
845 		    {
846 		      char *cp;
847 		      if (rm == 0)
848 			{
849 			  cp = stpcpy (mnebuf, "fmv.x.");
850 			  *cp++ = intwidthchar[width];
851 			}
852 		      else
853 			{
854 			  cp = stpcpy (mnebuf, "fclass.");
855 			  *cp++ = widthchar[width];
856 			}
857 		      *cp = '\0';
858 		      mne = mnebuf;
859 		      op[0] = REG (rd);
860 		      op[1] = FREG (rs1);
861 		    }
862 		  else if (func == 0x1e && width != 2 && rs2 == 0 && rm == 0)
863 		    {
864 		      char *cp = stpcpy (mnebuf, "fmv.");
865 		      *cp++ = intwidthchar[width];
866 		      strcpy (cp, ".x");
867 		      mne = mnebuf;
868 		      op[0] = FREG (rd);
869 		      op[1] = REG (rs1);
870 		    }
871 		  else if (func == 0x14)
872 		    {
873 		      uint32_t cmpop = (word >> 12) & 0x7;
874 		      if (cmpop < 3)
875 			{
876 			  static const char *const mnefpcmp[3] =
877 			    {
878 			      "fle", "flt", "feq"
879 			    };
880 			  char *cp = stpcpy (mnebuf, mnefpcmp[cmpop]);
881 			  *cp++ = '.';
882 			  *cp++ = widthchar[width];
883 			  *cp = '\0';
884 			  mne = mnebuf;
885 			  op[0] = REG (rd);
886 			  op[1] = FREG (rs1);
887 			  op[2] = FREG (rs2);
888 			}
889 		    }
890 		  else if (func == 0x04)
891 		    {
892 		      uint32_t cmpop = (word >> 12) & 0x7;
893 		      if (cmpop < 3)
894 			{
895 			  op[0] = FREG (rd);
896 			  op[1] = FREG (rs1);
897 
898 			  static const char *const mnefpcmp[3] =
899 			    {
900 			      "fsgnj.", "fsgnjn.", "fsgnjx."
901 			    };
902 			  static const char *const altsignmne[3] =
903 			    {
904 			      "fmv.", "fneg.", "fabs."
905 			    };
906 			  char *cp = stpcpy (mnebuf, rs1 == rs2 ? altsignmne[cmpop] : mnefpcmp[cmpop]);
907 			  *cp++ = widthchar[width];
908 			  *cp = '\0';
909 			  mne = mnebuf;
910 
911 			  if (rs1 != rs2)
912 			    op[2] = FREG (rs2);
913 			}
914 		    }
915 		  else if (func == 0x08 && width != 2 && rs2 <= 3 && rs2 != 2 && rs2 != width)
916 		    {
917 		      op[0] = FREG (rd);
918 		      op[1] = FREG (rs1);
919 		      char *cp = stpcpy (mnebuf, "fcvt.");
920 		      *cp++ = widthchar[width];
921 		      *cp++ = '.';
922 		      *cp++ = widthchar[rs2];
923 		      *cp = '\0';
924 		      mne = mnebuf;
925 		    }
926 		  else if ((func & 0x1d) == 0x18 && width != 2 && rs2 < 4)
927 		    {
928 		      char *cp = stpcpy (mnebuf, "fcvt.");
929 		      if (func == 0x18)
930 			{
931 			  *cp++ = rs2 >= 2 ? 'l' : 'w';
932 			  if ((rs2 & 1) == 1)
933 			    *cp++ = 'u';
934 			  *cp++ = '.';
935 			  *cp++ = widthchar[width];
936 			  *cp = '\0';
937 			  op[0] = REG (rd);
938 			  op[1] = FREG (rs1);
939 			}
940 		      else
941 			{
942 			  *cp++ = widthchar[width];
943 			  *cp++ = '.';
944 			  *cp++ = rs2 >= 2 ? 'l' : 'w';
945 			  if ((rs2 & 1) == 1)
946 			    *cp++ = 'u';
947 			  *cp = '\0';
948 			  op[0] = FREG (rd);
949 			  op[1] = REG (rs1);
950 			}
951 		      mne = mnebuf;
952 		      if (rm != 0x7 && (func == 0x18 || width == 0 || rs2 >= 2))
953 			op[2] = (char *) rndmode[rm];
954 		    }
955 		  else if (func == 0x0b && rs2 == 0)
956 		    {
957 		      op[0] = FREG (rd);
958 		      op[1] = FREG (rs1);
959 		      char *cp = stpcpy (mnebuf, "fsqrt.");
960 		      *cp++ = widthchar[width];
961 		      *cp = '\0';
962 		      mne = mnebuf;
963 		      if (rm != 0x7)
964 			op[2] = (char *) rndmode[rm];
965 		    }
966 		  else if (func == 0x05 && rm < 2)
967 		    {
968 		      op[0] = FREG (rd);
969 		      op[1] = FREG (rs1);
970 		      op[2] = FREG (rs2);
971 		      char *cp = stpcpy (mnebuf, rm == 0 ? "fmin." : "fmax.");
972 		      *cp++ = widthchar[width];
973 		      *cp = '\0';
974 		      mne = mnebuf;
975 		    }
976 		  else if (func == 0x14 && rm <= 0x2)
977 		    {
978 		      op[0] = REG (rd);
979 		      op[1] = FREG (rs1);
980 		      op[2] = FREG (rs2);
981 		      static const char *const fltcmpmne[3] =
982 			{
983 			  "fle.", "flt.", "feq."
984 			};
985 		      char *cp = stpcpy (mnebuf, fltcmpmne[rm]);
986 		      *cp++ = widthchar[width];
987 		      *cp = '\0';
988 		      mne = mnebuf;
989 		    }
990 		}
991 	      break;
992 	    case 0x18:
993 	      // BRANCH
994 	      rs1 = (word >> 15) & 0x1f;
995 	      op[0] = REG (rs1);
996 	      rs2 = (word >> 20) & 0x1f;
997 	      op[1] = REG (rs2);
998 	      opaddr = addr + (((UINT64_C (0) - (word >> 31)) << 12)
999 			       + ((word << 4) & 0x800)
1000 			       + ((word >> 20) & 0x7e0)
1001 			       + ((word >> 7) & 0x1e));
1002 	      // TODO translate address
1003 	      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr);
1004 	      op[2] = addrbuf;
1005 	      static const char *const branchmne[8] =
1006 		{
1007 		  "beq", "bne", NULL, NULL, "blt", "bge", "bltu", "bgeu"
1008 		};
1009 	      func = (word >> 12) & 0x7;
1010 	      mne = (char *) branchmne[func];
1011 	      if (rs1 == 0 && func == 5)
1012 		{
1013 		  op[0] = op[1];
1014 		  op[1] = op[2];
1015 		  op[2] = NULL;
1016 		  mne = "blez";
1017 		}
1018 	      else if (rs1 == 0 && func == 4)
1019 		{
1020 		  op[0] = op[1];
1021 		  op[1] = op[2];
1022 		  op[2] = NULL;
1023 		  mne = "bgtz";
1024 		}
1025 	      else if (rs2 == 0)
1026 		{
1027 		  if (func == 0 || func == 1 || func == 4 || func == 5)
1028 		    {
1029 		      op[1] = op[2];
1030 		      op[2] = NULL;
1031 		      strcpy (stpcpy (mnebuf, mne), "z");
1032 		      mne = mnebuf;
1033 		    }
1034 		}
1035 	      else if (func == 5 || func == 7)
1036 		{
1037 		  // binutils use these opcodes and the reverse parameter order
1038 		  char *tmp = op[0];
1039 		  op[0] = op[1];
1040 		  op[1] = tmp;
1041 		  mne = func == 5 ? "ble" : "bleu";
1042 		}
1043 	      break;
1044 	    case 0x19:
1045 	      // JALR
1046 	      if ((word & 0x7000) == 0)
1047 		{
1048 		  rd = (word >> 7) & 0x1f;
1049 		  rs1 = (word >> 15) & 0x1f;
1050 		  opaddr = (int32_t) word >> 20;
1051 		  size_t next = 0;
1052 		  if (rd > 1)
1053 		    op[next++] = REG (rd);
1054 		  if (opaddr == 0)
1055 		    {
1056 		      if (rs1 != 0 || next == 0)
1057 			op[next] = REG (rs1);
1058 		    }
1059 		  else
1060 		    {
1061 		      snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (rs1));
1062 		      op[next] = addrbuf;
1063 		    }
1064 		  mne = rd == 0 ? "jr" : "jalr";
1065 		}
1066 	      break;
1067 	    case 0x1b:
1068 	      // JAL
1069 	      rd = (word >> 7) & 0x1f;
1070 	      if (rd != 0)
1071 		op[0] = REG (rd);
1072 	      opaddr = addr + ((UINT64_C (0) - ((word >> 11) & 0x100000))
1073 			       | (word & 0xff000)
1074 			       | ((word >> 9) & 0x800)
1075 			       | ((word >> 20) & 0x7fe));
1076 	      // TODO translate address
1077 	      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr);
1078 	      op[rd != 0] = addrbuf;
1079 	      mne = rd == 0 ? "j" : "jal";
1080 	      break;
1081 	    case 0x1c:
1082 	      // SYSTEM
1083 	      rd = (word >> 7) & 0x1f;
1084 	      rs1 = (word >> 15) & 0x1f;
1085 	      if (word == 0x00000073)
1086 		mne = "ecall";
1087 	      else if (word == 0x00100073)
1088 		mne = "ebreak";
1089 	      else if (word == 0x00200073)
1090 		mne = "uret";
1091 	      else if (word == 0x10200073)
1092 		mne = "sret";
1093 	      else if (word == 0x30200073)
1094 		mne = "mret";
1095 	      else if (word == 0x10500073)
1096 		mne = "wfi";
1097 	      else if ((word & 0x3000) == 0x2000 && rs1 == 0)
1098 		{
1099 		  uint32_t csr = word >> 20;
1100 		  if (/* csr >= 0x000 && */ csr <= 0x007)
1101 		    {
1102 		      static const char *const unprivrw[4] =
1103 			{
1104 			  NULL, "frflags", "frrm", "frsr",
1105 			};
1106 		      mne = (char *) unprivrw[csr - 0x000];
1107 		    }
1108 		  else if (csr >= 0xc00 && csr <= 0xc03)
1109 		    {
1110 		      static const char *const unprivrolow[3] =
1111 			{
1112 			  "rdcycle", "rdtime", "rdinstret"
1113 			};
1114 		      mne = (char *) unprivrolow[csr - 0xc00];
1115 		    }
1116 		  op[0] = REG ((word >> 7) & 0x1f);
1117 		}
1118 	      else if ((word & 0x3000) == 0x1000 && rd == 0)
1119 		{
1120 		  uint32_t csr = word >> 20;
1121 		  if (/* csr >= 0x000 && */ csr <= 0x003)
1122 		    {
1123 		      static const char *const unprivrs[4] =
1124 			{
1125 			  NULL, "fsflags", "fsrm", "fssr",
1126 			};
1127 		      static const char *const unprivrsi[4] =
1128 			{
1129 			  NULL, "fsflagsi", "fsrmi", NULL
1130 			};
1131 		      mne = (char *) ((word & 0x4000) == 0 ? unprivrs : unprivrsi)[csr - 0x000];
1132 
1133 		      if ((word & 0x4000) == 0)
1134 			op[0] = REG ((word >> 15) & 0x1f);
1135 		      else
1136 			{
1137 			  snprintf (immbuf, sizeof (immbuf), "%" PRIu32, (word >> 15) & 0x1f);
1138 			  op[0] = immbuf;
1139 			}
1140 		    }
1141 		}
1142 	      if (mne == NULL && (word & 0x3000) != 0)
1143 		{
1144 		  static const char *const mnecsr[8] =
1145 		    {
1146 		      NULL, "csrrw", "csrrs", "csrrc",
1147 		      NULL, "csrrwi", "csrrsi", "csrrci"
1148 		    };
1149 		  static const struct known_csrs known[] =
1150 		    {
1151 		      // This list must remain sorted by NR.
1152 		      { 0x000, "ustatus" },
1153 		      { 0x001, "fflags" },
1154 		      { 0x002, "fram" },
1155 		      { 0x003, "fcsr" },
1156 		      { 0x004, "uie" },
1157 		      { 0x005, "utvec" },
1158 		      { 0x040, "uscratch" },
1159 		      { 0x041, "uepc" },
1160 		      { 0x042, "ucause" },
1161 		      { 0x043, "utval" },
1162 		      { 0x044, "uip" },
1163 		      { 0x100, "sstatus" },
1164 		      { 0x102, "sedeleg" },
1165 		      { 0x103, "sideleg" },
1166 		      { 0x104, "sie" },
1167 		      { 0x105, "stvec" },
1168 		      { 0x106, "scounteren" },
1169 		      { 0x140, "sscratch" },
1170 		      { 0x141, "sepc" },
1171 		      { 0x142, "scause" },
1172 		      { 0x143, "stval" },
1173 		      { 0x144, "sip" },
1174 		      { 0x180, "satp" },
1175 		      { 0x200, "vsstatus" },
1176 		      { 0x204, "vsie" },
1177 		      { 0x205, "vstvec" },
1178 		      { 0x240, "vsscratch" },
1179 		      { 0x241, "vsepc" },
1180 		      { 0x242, "vscause" },
1181 		      { 0x243, "vstval" },
1182 		      { 0x244, "vsip" },
1183 		      { 0x280, "vsatp" },
1184 		      { 0x600, "hstatus" },
1185 		      { 0x602, "hedeleg" },
1186 		      { 0x603, "hideleg" },
1187 		      { 0x605, "htimedelta" },
1188 		      { 0x606, "hcounteren" },
1189 		      { 0x615, "htimedeltah" },
1190 		      { 0x680, "hgatp" },
1191 		      { 0xc00, "cycle" },
1192 		      { 0xc01, "time" },
1193 		      { 0xc02, "instret" },
1194 		      { 0xc03, "hpmcounter3" },
1195 		      { 0xc04, "hpmcounter4" },
1196 		      { 0xc05, "hpmcounter5" },
1197 		      { 0xc06, "hpmcounter6" },
1198 		      { 0xc07, "hpmcounter7" },
1199 		      { 0xc08, "hpmcounter8" },
1200 		      { 0xc09, "hpmcounter9" },
1201 		      { 0xc0a, "hpmcounter10" },
1202 		      { 0xc0b, "hpmcounter11" },
1203 		      { 0xc0c, "hpmcounter12" },
1204 		      { 0xc0d, "hpmcounter13" },
1205 		      { 0xc0e, "hpmcounter14" },
1206 		      { 0xc0f, "hpmcounter15" },
1207 		      { 0xc10, "hpmcounter16" },
1208 		      { 0xc11, "hpmcounter17" },
1209 		      { 0xc12, "hpmcounter18" },
1210 		      { 0xc13, "hpmcounter19" },
1211 		      { 0xc14, "hpmcounter20" },
1212 		      { 0xc15, "hpmcounter21" },
1213 		      { 0xc16, "hpmcounter22" },
1214 		      { 0xc17, "hpmcounter23" },
1215 		      { 0xc18, "hpmcounter24" },
1216 		      { 0xc19, "hpmcounter25" },
1217 		      { 0xc1a, "hpmcounter26" },
1218 		      { 0xc1b, "hpmcounter27" },
1219 		      { 0xc1c, "hpmcounter28" },
1220 		      { 0xc1d, "hpmcounter29" },
1221 		      { 0xc1e, "hpmcounter30" },
1222 		      { 0xc1f, "hpmcounter31" },
1223 		      { 0xc80, "cycleh" },
1224 		      { 0xc81, "timeh" },
1225 		      { 0xc82, "instreth" },
1226 		      { 0xc83, "hpmcounter3h" },
1227 		      { 0xc84, "hpmcounter4h" },
1228 		      { 0xc85, "hpmcounter5h" },
1229 		      { 0xc86, "hpmcounter6h" },
1230 		      { 0xc87, "hpmcounter7h" },
1231 		      { 0xc88, "hpmcounter8h" },
1232 		      { 0xc89, "hpmcounter9h" },
1233 		      { 0xc8a, "hpmcounter10h" },
1234 		      { 0xc8b, "hpmcounter11h" },
1235 		      { 0xc8c, "hpmcounter12h" },
1236 		      { 0xc8d, "hpmcounter13h" },
1237 		      { 0xc8e, "hpmcounter14h" },
1238 		      { 0xc8f, "hpmcounter15h" },
1239 		      { 0xc90, "hpmcounter16h" },
1240 		      { 0xc91, "hpmcounter17h" },
1241 		      { 0xc92, "hpmcounter18h" },
1242 		      { 0xc93, "hpmcounter19h" },
1243 		      { 0xc94, "hpmcounter20h" },
1244 		      { 0xc95, "hpmcounter21h" },
1245 		      { 0xc96, "hpmcounter22h" },
1246 		      { 0xc97, "hpmcounter23h" },
1247 		      { 0xc98, "hpmcounter24h" },
1248 		      { 0xc99, "hpmcounter25h" },
1249 		      { 0xc9a, "hpmcounter26h" },
1250 		      { 0xc9b, "hpmcounter27h" },
1251 		      { 0xc9c, "hpmcounter28h" },
1252 		      { 0xc9d, "hpmcounter29h" },
1253 		      { 0xc9e, "hpmcounter30h" },
1254 		      { 0xc9f, "hpmcounter31h" },
1255 		    };
1256 		  uint32_t csr = word >> 20;
1257 		  uint32_t instr = (word >> 12) & 0x7;
1258 		  size_t last = 0;
1259 		  if (rd != 0)
1260 		    op[last++] = REG (rd);
1261 		  struct known_csrs key = { csr, NULL };
1262 		  struct known_csrs *found = bsearch (&key, known,
1263 						      sizeof (known) / sizeof (known[0]),
1264 						      sizeof (known[0]),
1265 						      compare_csr);
1266 		  if (found)
1267 		    op[last] = (char *) found->name;
1268 		  else
1269 		    {
1270 		      snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx32, csr);
1271 		      op[last] = addrbuf;
1272 		    }
1273 		  ++last;
1274 		  if ((word & 0x4000) == 0)
1275 		    op[last] = REG ((word >> 15) & 0x1f);
1276 		  else
1277 		    {
1278 		      snprintf (immbuf, sizeof (immbuf), "%" PRIu32, (word >> 15) & UINT32_C(0x1f));
1279 		      op[last] = immbuf;
1280 		    }
1281 		  if (instr == 1 && rd == 0)
1282 		    mne = "csrw";
1283 		  else if (instr == 2 && rd == 0)
1284 		    mne = "csrs";
1285 		  else if (instr == 6 && rd == 0)
1286 		    mne = "csrsi";
1287 		  else if (instr == 2 && rs1 == 0)
1288 		    mne = "csrr";
1289 		  else if (instr == 3 && rd == 0)
1290 		    mne = "csrc";
1291 		  else
1292 		    mne = (char *) mnecsr[instr];
1293 		}
1294 	      break;
1295 	    default:
1296 	      break;
1297 	    }
1298 
1299 	  if (strp == NULL && mne == NULL)
1300 	    {
1301 	      len = snprintf (addrbuf, sizeof (addrbuf), "0x%08" PRIx32, word);
1302 	      strp = addrbuf;
1303 	    }
1304 	}
1305       else
1306 	{
1307 	  // No instruction encodings defined for these sizes yet.
1308 	  char *cp = stpcpy (mnebuf, "0x");
1309 	  assert (length % 2 == 0);
1310 	  for (size_t i = 0; i < length; i += 2)
1311 	    cp += snprintf (cp, mnebuf + sizeof (mnebuf) - cp, "%04" PRIx16,
1312 			    read_2ubyte_unaligned (data + i));
1313 	  strp = mnebuf;
1314 	  len = cp - mnebuf;
1315 	}
1316 
1317       if (strp == NULL)
1318 	{
1319 
1320 	  if (0)
1321 	    {
1322 	      /* Resize the buffer.  */
1323 	      char *oldbuf;
1324 	    enomem:
1325 	      oldbuf = buf;
1326 	      if (buf == initbuf)
1327 		buf = malloc (2 * bufsize);
1328 	      else
1329 		buf = realloc (buf, 2 * bufsize);
1330 	      if (buf == NULL)
1331 		{
1332 		  buf = oldbuf;
1333 		  retval = ENOMEM;
1334 		  goto do_ret;
1335 		}
1336 	      bufsize *= 2;
1337 
1338 	      bufcnt = 0;
1339 	    }
1340 
1341 	  unsigned long string_end_idx = 0;
1342 	  fmt = save_fmt;
1343 	  const char *deferred_start = NULL;
1344 	  size_t deferred_len = 0;
1345 	  // XXX Can we get this from color.c?
1346 	  static const char color_off[] = "\e[0m";
1347 	  while (*fmt != '\0')
1348 	    {
1349 	      if (*fmt != '%')
1350 		{
1351 		  char ch = *fmt++;
1352 		  if (ch == '\\')
1353 		    {
1354 		      switch ((ch = *fmt++))
1355 			{
1356 			case '0' ... '7':
1357 			  {
1358 			    int val = ch - '0';
1359 			    ch = *fmt;
1360 			    if (ch >= '0' && ch <= '7')
1361 			      {
1362 				val *= 8;
1363 				val += ch - '0';
1364 				ch = *++fmt;
1365 				if (ch >= '0' && ch <= '7' && val < 32)
1366 				  {
1367 				    val *= 8;
1368 				    val += ch - '0';
1369 				    ++fmt;
1370 				  }
1371 			      }
1372 			    ch = val;
1373 			  }
1374 			  break;
1375 
1376 			case 'n':
1377 			  ch = '\n';
1378 			  break;
1379 
1380 			case 't':
1381 			  ch = '\t';
1382 			  break;
1383 
1384 			default:
1385 			  retval = EINVAL;
1386 			  goto do_ret;
1387 			}
1388 		    }
1389 		  else if (ch == '\e' && *fmt == '[')
1390 		    {
1391 		      deferred_start = fmt - 1;
1392 		      do
1393 			++fmt;
1394 		      while (*fmt != 'm' && *fmt != '\0');
1395 
1396 		      if (*fmt == 'm')
1397 			{
1398 			  deferred_len = ++fmt - deferred_start;
1399 			  continue;
1400 			}
1401 
1402 		      fmt = deferred_start + 1;
1403 		      deferred_start = NULL;
1404 		    }
1405 		  ADD_CHAR (ch);
1406 		  continue;
1407 		}
1408 	      ++fmt;
1409 
1410 	      int width = 0;
1411 	      while (isdigit (*fmt))
1412 		width = width * 10 + (*fmt++ - '0');
1413 
1414 	      int prec = 0;
1415 	      if (*fmt == '.')
1416 		while (isdigit (*++fmt))
1417 		  prec = prec * 10 + (*fmt - '0');
1418 
1419 	      size_t start_idx = bufcnt;
1420 	      size_t non_printing = 0;
1421 	      switch (*fmt++)
1422 		{
1423 		case 'm':
1424 		  if (deferred_start != NULL)
1425 		    {
1426 		      ADD_NSTRING (deferred_start, deferred_len);
1427 		      non_printing += deferred_len;
1428 		    }
1429 
1430 		  ADD_STRING (mne);
1431 
1432 		  if (deferred_start != NULL)
1433 		    {
1434 		      ADD_STRING (color_off);
1435 		      non_printing += strlen (color_off);
1436 		    }
1437 
1438 		  string_end_idx = bufcnt;
1439 		  break;
1440 
1441 		case 'o':
1442 		  if (op[prec - 1] != NULL)
1443 		    {
1444 		      if (deferred_start != NULL)
1445 			{
1446 			  ADD_NSTRING (deferred_start, deferred_len);
1447 			  non_printing += deferred_len;
1448 			}
1449 
1450 		      ADD_STRING (op[prec - 1]);
1451 
1452 		      if (deferred_start != NULL)
1453 			{
1454 			  ADD_STRING (color_off);
1455 			  non_printing += strlen (color_off);
1456 			}
1457 
1458 		      string_end_idx = bufcnt;
1459 		    }
1460 		  else
1461 		    bufcnt = string_end_idx;
1462 		  break;
1463 
1464 		case 'e':
1465 		  string_end_idx = bufcnt;
1466 		  break;
1467 
1468 		case 'a':
1469 		  /* Pad to requested column.  */
1470 		  while (bufcnt - non_printing < (size_t) width)
1471 		    ADD_CHAR (' ');
1472 		  width = 0;
1473 		  break;
1474 
1475 		case 'l':
1476 		  // TODO
1477 		  break;
1478 
1479 		default:
1480 		  abort();
1481 		}
1482 
1483 	      /* Pad according to the specified width.  */
1484 	      while (bufcnt - non_printing < start_idx + width)
1485 		ADD_CHAR (' ');
1486 	    }
1487 
1488 	  strp = buf;
1489 	  len = bufcnt;
1490 	}
1491 
1492       addr += length;
1493       *startp = data + length;
1494       retval = outcb (strp, len, outcbarg);
1495       if (retval != 0)
1496 	break;
1497     }
1498 
1499  do_ret:
1500   if (buf != initbuf)
1501     free (buf);
1502 
1503   return retval;
1504 }
1505