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