Coverage Report

Created: 2025-08-24 06:28

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