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