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