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
73static 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
84static 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
95struct known_csrs
96  {
97    uint16_t nr;
98    const char *name;
99  };
100
101static 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
111int
112riscv_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