I'll check in the attached patch which implements a disassembler for RISC-V. It also fixes a problem in the x86 disassember, exposed through the additions needed for RISC-V.
Since aside rth, who added the BPF disassembler, no one beside me ever worked on that code I will push the changes as soon as I can.
diff --git a/backends/riscv_init.c b/backends/riscv_init.c index 9aaec9ce..9be5c6f2 100644 --- a/backends/riscv_init.c +++ b/backends/riscv_init.c @@ -58,6 +58,7 @@ riscv_init (Elf *elf, HOOK (eh, reloc_simple_type); HOOK (eh, register_info); HOOK (eh, abi_cfi); + HOOK (eh, disasm); /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ eh->frame_nregs = 66; HOOK (eh, check_special_symbol); diff --git a/lib/color.c b/lib/color.c index 20b9698a..2cb41eba 100644 --- a/lib/color.c +++ b/lib/color.c @@ -72,6 +72,8 @@ char *color_operand = NULL; char *color_operand1 = ""; char *color_operand2 = ""; char *color_operand3 = ""; +char *color_operand4 = ""; +char *color_operand5 = ""; char *color_label = ""; char *color_undef = ""; char *color_undef_tls = ""; @@ -167,8 +169,10 @@ valid arguments are:\n\ E (m, mnemonic), E (o, operand), E (o1, operand1), - E (o1, operand2), - E (o1, operand3), + E (o2, operand2), + E (o3, operand3), + E (o4, operand4), + E (o5, operand5), E (l, label), E (u, undef), E (ut, undef_tls), @@ -205,6 +209,10 @@ valid arguments are:\n\ color_operand2 = color_operand; if (color_operand3[0] == '\0') color_operand3 = color_operand; + if (color_operand4[0] == '\0') + color_operand4 = color_operand; + if (color_operand5[0] == '\0') + color_operand5 = color_operand; } } #if 0 @@ -216,7 +224,7 @@ valid arguments are:\n\ color_mnemonic = xstrdup ("\e[38;5;202;1m"); color_operand1 = xstrdup ("\e[38;5;220m"); color_operand2 = xstrdup ("\e[38;5;48m"); - color_operand3 = xstrdup ("\e[38;5;112m"); + color_operand = xstrdup ("\e[38;5;112m"); color_label = xstrdup ("\e[38;5;21m"); } #endif diff --git a/lib/color.h b/lib/color.h index 3872eb0a..cb241435 100644 --- a/lib/color.h +++ b/lib/color.h @@ -50,6 +50,8 @@ extern char *color_mnemonic; extern char *color_operand1; extern char *color_operand2; extern char *color_operand3; +extern char *color_operand4; +extern char *color_operand5; extern char *color_label; extern char *color_undef; extern char *color_undef_tls; diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am index 88717361..03c71ea3 100644 --- a/libcpu/Makefile.am +++ b/libcpu/Makefile.am @@ -42,7 +42,7 @@ noinst_LIBRARIES = libcpu.a libcpu_pic.a noinst_HEADERS = i386_dis.h x86_64_dis.h -libcpu_a_SOURCES = i386_disasm.c x86_64_disasm.c bpf_disasm.c +libcpu_a_SOURCES = i386_disasm.c x86_64_disasm.c bpf_disasm.c riscv_disasm.c libcpu_pic_a_SOURCES = am_libcpu_pic_a_OBJECTS = $(libcpu_a_SOURCES:.c=.os) diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c index a7e03f95..8a206398 100644 --- a/libcpu/i386_disasm.c +++ b/libcpu/i386_disasm.c @@ -1030,7 +1030,7 @@ i386_disasm (Ebl *ebl __attribute__((unused)), string_end_idx = bufcnt; } else - bufcnt = string_end_idx; + start_idx = bufcnt = string_end_idx; break; case 'e': diff --git a/libcpu/riscv_disasm.c b/libcpu/riscv_disasm.c new file mode 100644 index 00000000..bc4e02e5 --- /dev/null +++ b/libcpu/riscv_disasm.c @@ -0,0 +1,1501 @@ +/* Disassembler for RISC-V. + Copyright (C) 2019 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drep...@redhat.com>, 2019. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../libebl/libeblP.h" + +#define MACHINE_ENCODING __LITTLE_ENDIAN +#include "memory-access.h" + + +#define ADD_CHAR(ch) \ + do { \ + if (unlikely (bufcnt == bufsize)) \ + goto enomem; \ + buf[bufcnt++] = (ch); \ + } while (0) + +#define ADD_STRING(str) \ + do { \ + const char *_str0 = (str); \ + size_t _len0 = strlen (_str0); \ + ADD_NSTRING (_str0, _len0); \ + } while (0) + +#define ADD_NSTRING(str, len) \ + do { \ + const char *_str = (str); \ + size_t _len = (len); \ + if (unlikely (bufcnt + _len > bufsize)) \ + goto enomem; \ + memcpy (buf + bufcnt, _str, _len); \ + bufcnt += _len; \ + } while (0) + + +static const char *regnames[32] = + { + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" + }; +#define REG(nr) ((char *) regnames[nr]) +#define REGP(nr) REG (8 + (nr)) + + +static const char *fregnames[32] = + { + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", + "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" + }; +#define FREG(nr) ((char *) fregnames[nr]) +#define FREGP(nr) FREG (8 + (nr)) + + +struct known_csrs + { + uint16_t nr; + const char *name; + }; + +static int compare_csr (const void *a, const void *b) +{ + const struct known_csrs *ka = (const struct known_csrs *) a; + const struct known_csrs *kb = (const struct known_csrs *) b; + if (ka->nr < kb->nr) + return -1; + return ka->nr == kb->nr ? 0 : 1; +} + + +int +riscv_disasm (Ebl *ebl, + const uint8_t **startp, const uint8_t *end, GElf_Addr addr, + const char *fmt, DisasmOutputCB_t outcb, + DisasmGetSymCB_t symcb __attribute__((unused)), + void *outcbarg, void *symcbarg __attribute__((unused))) +{ + const char *const save_fmt = fmt; + +#define BUFSIZE 512 + char initbuf[BUFSIZE]; + size_t bufcnt; + size_t bufsize = BUFSIZE; + char *buf = initbuf; + + int retval = 0; + while (1) + { + const uint8_t *data = *startp; + assert (data <= end); + if (data + 2 > end) + { + if (data != end) + retval = -1; + break; + } + uint16_t first = read_2ubyte_unaligned (data); + + // Determine length. + size_t length; + if ((first & 0x3) != 0x3) + length = 2; + else if ((first & 0x1f) != 0x1f) + length = 4; + else if ((first & 0x3f) != 0x3f) + length = 6; + else if ((first & 0x7f) != 0x7f) + length = 8; + else + { + uint16_t nnn = (first >> 12) & 0x7; + if (nnn != 0x7) + length = 10 + 2 * nnn; + else + // This is invalid as of the RISC-V spec on 2019-06-21. + // The instruction is at least 192 bits in size so use + // this minimum size. + length = 24; + } + if (data + length > end) + { + retval = -1; + break; + } + + char *mne = NULL; + char mnebuf[32]; + char *op[5] = { NULL, NULL, NULL, NULL, NULL }; + char immbuf[32]; + size_t len; + char *strp = NULL; + char addrbuf[32]; + bufcnt = 0; + int64_t opaddr; + if (length == 2) + { + size_t idx = (first >> 13) * 3 + (first & 0x3); + switch (idx) + { + uint16_t rd; + uint16_t rs1; + uint16_t rs2; + + case 0: + if ((first & 0x1fe0) != 0) + { + mne = "addi"; + op[0] = REGP ((first & 0x1c) >> 2); + op[1] = REG (2); + opaddr = (((first >> 1) & 0x3c0) + | ((first >> 7) & 0x30) + | ((first >> 2) & 0x8) + | ((first >> 4) & 0x4)); + snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64, opaddr); + op[2] = addrbuf; + } + else if (first == 0) + mne = "unimp"; + break; + case 1: + rs1 = (first >> 7) & 0x1f; + int16_t nzimm = ((0 - ((first >> 7) & 0x20)) + | ((first >> 2) & 0x1f)); + if (rs1 == 0) + mne = nzimm == 0 ? "nop" : "c.nop"; + else + { + mne = nzimm == 0 ? "c.addi" : "addi"; + op[0] = op[1] = REG (rs1); + snprintf (addrbuf, sizeof (addrbuf), "%" PRId16, nzimm); + op[2] = addrbuf; + } + break; + case 2: + rs1 = (first >> 7) & 0x1f; + op[0] = op[1] = REG (rs1); + opaddr = ((first >> 7) & 0x20) | ((first >> 2) & 0x1f); + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr); + op[2] = addrbuf; + mne = rs1 == 0 ? "c.slli" : "slli"; + break; + case 3: + op[0] = FREGP ((first >> 2) & 0x7); + opaddr = ((first << 1) & 0xc0) | ((first >> 7) & 0x38); + snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)", + opaddr, REGP ((first >> 7) & 0x7)); + op[1] = addrbuf; + mne = "fld"; + break; + case 4: + if (ebl->class == ELFCLASS32) + { + mne = "jal"; + opaddr = (((first << 3) & 0x20) | ((first >> 2) & 0xe) + | ((first << 1) & 0x80) | ((first >> 1) | 0x40) + | ((first << 2) & 0x400) | (first & 0xb00) + | ((first >> 6) & 0x10)); + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr); + op[0] = addrbuf; + } + else + { + int32_t imm = (((UINT32_C (0) - ((first >> 12) & 0x1)) << 5) + | ((first >> 2) & 0x1f)); + uint16_t reg = (first >> 7) & 0x1f; + if (reg == 0) + { + // Reserved + len = snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx16, first); + strp = addrbuf; + } + else + { + if (imm == 0) + mne = "sext.w"; + else + { + mne = "addiw"; + snprintf (addrbuf, sizeof (addrbuf), "%" PRId32, imm); + op[2] = addrbuf; + } + op[0] = op[1] = REG (reg); + } + } + break; + case 5: + op[0] = FREG ((first >> 7) & 0x1f); + opaddr = ((first << 4) & 0x1c0) | ((first >> 7) & 0x20) | ((first >> 2) & 0x18); + snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)", opaddr, REG (2)); + op[1] = addrbuf; + mne = "fld"; + break; + case 6: + case 18: + mne = idx == 6 ? "lw" : "sw"; + op[0] = REGP ((first >> 2) & 0x7); + opaddr = (((first >> 7) & 0x38) | ((first << 1) & 0x40) + | ((first >> 4) & 0x4)); + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", + opaddr, REGP ((first >> 7) & 0x7)); + op[1] = addrbuf; + break; + case 7: + mne = (first & 0xf80) == 0 ? "c.li" : "li"; + op[0] = REG((first >> 7) & 0x1f); + snprintf (addrbuf, sizeof (addrbuf), "%" PRId16, + (UINT16_C (0) - ((first >> 7) & 0x20)) | ((first >> 2) & 0x1f)); + op[1] = addrbuf; + break; + case 8: + rd = ((first >> 7) & 0x1f); + if (rd == 0) + { + len = snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx16, first); + strp = addrbuf; + } + else + { + uint16_t uimm = (((first << 4) & 0xc0) + | ((first >> 7) & 0x20) + | ((first >> 2) & 0x1c)); + mne = "lw"; + op[0] = REG (rd); + snprintf (addrbuf, sizeof (addrbuf), "%" PRIu16 "(%s)", uimm, REG (2)); + op[1] = addrbuf; + } + break; + case 9: + if (ebl->class == ELFCLASS32) + { + mne = "flw"; + op[0] = FREGP ((first >> 2) & 0x7); + opaddr = (((first << 1) & 0x40) + | ((first >> 7) & 0x38) + | ((first >> 4) & 0x4)); + } + else + { + mne = "ld"; + op[0] = REGP ((first >> 2) & 0x7); + opaddr = ((first >> 7) & 0x38) | ((first << 1) & 0xc0); + } + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", + opaddr, REGP ((first >> 7) & 0x7)); + op[1] = addrbuf; + break; + case 10: + if ((first & 0xf80) == (2 << 7)) + { + mne = "addi"; + op[0] = op[1] = REG (2); + opaddr = (((first >> 2) & 0x10) | ((first << 3) & 0x20) + | ((first << 1) & 0x40) | ((first << 4) & 0x180) + | ((UINT64_C (0) - ((first >> 12) & 0x1)) << 9)); + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64, opaddr); + op[2] = addrbuf; + } + else + { + mne = "lui"; + op[0] = REG((first & 0xf80) >> 7); + opaddr = (((UINT64_C (0) - ((first >> 12) & 0x1)) & ~0x1f) + | ((first >> 2) & 0x1f)); + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr & 0xfffff); + op[1] = addrbuf; + } + break; + case 11: + if (ebl->class == ELFCLASS32) + { + mne = "flw"; + op[0] = FREG ((first >> 7) & 0x1f); + opaddr = (((first << 4) & 0xc0) + | ((first >> 7) & 0x20) + | ((first >> 2) & 0x1c)); + } + else + { + mne = "ld"; + op[0] = REG ((first >> 7) & 0x1f); + opaddr = (((first << 4) & 0x1c0) + | ((first >> 7) & 0x20) + | ((first >> 2) & 0x18)); + } + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (2)); + op[1] = addrbuf; + break; + case 13: + if ((first & 0xc00) != 0xc00) + { + int16_t imm = ((first >> 7) & 0x20) | ((first >> 2) & 0x1f); + if ((first & 0xc00) == 0x800) + { + imm |= 0 - (imm & 0x20); + mne = "andi"; + snprintf (addrbuf, sizeof (addrbuf), "%" PRId16, imm); + } + else + { + if (ebl->class != ELFCLASS32 || imm < 32) + { + mne = (first & 0x400) ? "srai" : "srli"; + if (imm == 0) + { + strcpy (stpcpy (mnebuf, "c."), mne); + mne = mnebuf; + } + } + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx16, imm); + } + op[2] = addrbuf; + } + else + { + op[2] = REGP ((first >> 2) & 0x7); + static const char *const arithmne[8] = + { + "sub", "xor", "or", "and", "subw", "addw", NULL, NULL + }; + mne = (char *) arithmne[((first >> 10) & 0x4) | ((first >> 5) & 0x3)]; + } + op[0] = op[1] = REGP ((first >> 7) & 0x7); + break; + case 14: + rs1 = (first >> 7) & 0x1f; + rs2 = (first >> 2) & 0x1f; + op[0] = REG (rs1); + if ((first & 0x1000) == 0) + { + if (rs2 == 0) + { + op[1] = NULL; + if (rs1 == 1) + { + mne = "ret"; + op[0] = NULL; + } + else + mne = "jr"; + } + else + { + mne = rs1 != 0 ? "mv" : "c.mv"; + op[1] = REG (rs2); + } + } + else + { + if (rs2 == 0) + { + if (rs1 == 0) + { + mne = "ebreak"; + op[0] = op[1] = NULL; + } + else + mne = "jalr"; + } + else + { + mne = rs1 != 0 ? "add" : "c.add"; + op[2] = REG (rs2); + op[1] = op[0]; + } + } + break; + case 15: + op[0] = FREGP ((first >> 2) & 0x7); + opaddr = ((first << 1) & 0xc0) | ((first >> 7) & 0x38); + snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)", + opaddr, REGP ((first >> 7) & 0x7)); + op[1] = addrbuf; + mne = "fsd"; + break; + case 16: + opaddr = (((INT64_C (0) - ((first >> 12) & 0x1)) << 11) + | ((first << 2) & 0x400) + | ((first >> 1) & 0x300) + | ((first << 1) & 0x80) + | ((first >> 1) & 0x40) + | ((first << 3) & 0x20) + | ((first >> 7) & 0x10) + | ((first >> 2) & 0xe)); + mne = "j"; + // TODO translate address + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, addr + opaddr); + op[0] = addrbuf; + break; + case 17: + op[0] = FREG ((first >> 2) & 0x1f); + opaddr = ((first >> 1) & 0x1c0) | ((first >> 7) & 0x38); + snprintf (addrbuf, sizeof (addrbuf), "%" PRIu64 "(%s)", opaddr, REG (2)); + op[1] = addrbuf; + mne = "fsd"; + break; + case 19: + case 22: + mne = idx == 19 ? "beqz" : "bnez"; + op[0] = REG (8 + ((first >> 7) & 0x7)); + opaddr = addr + (((UINT64_C (0) - ((first >> 12) & 0x1)) & ~0xff) + | ((first << 1) & 0xc0) | ((first << 3) & 0x20) + | ((first >> 7) & 0x18) | ((first >> 2) & 0x6)); + // TODO translate address + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr); + op[1] = addrbuf; + break; + case 20: + op[0] = REG ((first >> 2) & 0x1f); + opaddr = ((first >> 1) & 0xc0) | ((first >> 7) & 0x3c); + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (2)); + op[1] = addrbuf; + mne = "sw"; + break; + case 21: + if (idx == 18 || ebl->class == ELFCLASS32) + { + mne = "fsw"; + op[0] = FREGP ((first >> 2) & 0x7); + opaddr = (((first >> 7) & 0x38) | ((first << 1) & 0x40) + | ((first >> 4) & 0x4)); + } + else + { + mne = "sd"; + op[0] = REGP ((first >> 2) & 0x7); + opaddr = ((first >> 7) & 0x38) | ((first << 1) & 0xc0); + } + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", + opaddr, REGP ((first >> 7) & 0x7)); + op[1] = addrbuf; + break; + case 23: + if (idx == 18 || ebl->class == ELFCLASS32) + { + mne = "fsw"; + op[0] = FREG ((first & 0x7c) >> 2); + opaddr = ((first & 0x1e00) >> 7) | ((first & 0x180) >> 1); + } + else + { + mne = "sd"; + op[0] = REG ((first & 0x7c) >> 2); + opaddr = ((first & 0x1c00) >> 7) | ((first & 0x380) >> 1); + } + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (2)); + op[1] = addrbuf; + break; + default: + break; + } + + if (strp == NULL && mne == NULL) + { + len = snprintf (immbuf, sizeof (immbuf), "0x%04" PRIx16, first); + strp = immbuf; + } + } + else if (length == 4) + { + uint32_t word = read_4ubyte_unaligned (data); + size_t idx = (word >> 2) & 0x1f; + + switch (idx) + { + static const char widthchar[4] = { 's', 'd', '\0', 'q' }; + static const char intwidthchar[4] = { 'w', 'd', '\0', 'q' }; + static const char *const rndmode[8] = { "rne", "rtz", "rdn", "rup", "rmm", "???", "???", "dyn" }; + uint32_t rd; + uint32_t rs1; + uint32_t rs2; + uint32_t rs3; + uint32_t func; + + case 0x00: + case 0x01: + // LOAD and LOAD-FP + rd = (word >> 7) & 0x1f; + op[0] = idx == 0x00 ? REG (rd) : FREG (rd); + opaddr = ((int32_t) word) >> 20; + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", + opaddr, REG ((word >> 15) & 0x1f)); + op[1] = addrbuf; + func = (word >> 12) & 0x7; + static const char *const loadmne[8] = + { + "lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", NULL + }; + static const char *const floadmne[8] = + { + NULL, NULL, "flw", "fld", "flq", NULL, NULL, NULL + }; + mne = (char *) (idx == 0x00 ? loadmne[func] : floadmne[func]); + break; + case 0x03: + // MISC-MEM + rd = (word >> 7) & 0x1f; + rs1 = (word >> 15) & 0x1f; + func = (word >> 12) & 0x7; + + if (word == 0x8330000f) + mne = "fence.tso"; + else if (word == 0x0000100f) + mne = "fence.i"; + else if (func == 0 && rd == 0 && rs1 == 0 && (word & 0xf0000000) == 0) + { + static const char *const order[16] = + { + "unknown", "w", "r", "rw", "o", "ow", "or", "orw", + "i", "iw", "ir", "irw", "io", "iow", "ior", "iorw" + }; + uint32_t pred = (word >> 20) & 0xf; + uint32_t succ = (word >> 24) & 0xf; + if (pred != 0xf || succ != 0xf) + { + op[0] = (char *) order[succ]; + op[1] = (char *) order[pred]; + } + mne = "fence"; + } + break; + case 0x04: + case 0x06: + // OP-IMM and OP-IMM32 + rd = (word >> 7) & 0x1f; + op[0] = REG (rd); + rs1 = (word >> 15) & 0x1f; + op[1] = REG (rs1); + opaddr = ((int32_t) word) >> 20; + static const char *const opimmmne[8] = + { + "addi", NULL, "slti", "sltiu", "xori", NULL, "ori", "andi" + }; + func = (word >> 12) & 0x7; + mne = (char *) opimmmne[func]; + if (mne == NULL) + { + const uint64_t shiftmask = ebl->class == ELFCLASS32 ? 0x1f : 0x3f; + if (func == 0x1 && (opaddr & ~shiftmask) == 0) + mne = "slli"; + else if (func == 0x5 && (opaddr & ~shiftmask) == 0) + mne = "srli"; + else if (func == 0x5 && (opaddr & ~shiftmask) == 0x400) + mne = "srai"; + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr & shiftmask); + op[2] = addrbuf; + } + else if (func == 0x0 && (rd != 0 || idx == 0x06) && rs1 == 0 && rd != 0) + { + mne = "li"; + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64, opaddr); + op[1] = addrbuf; + } + else if (func == 0x00 && opaddr == 0) + { + if (idx == 0x06) + mne ="sext."; + else if (rd == 0) + { + mne = "nop"; + op[0] = op[1] = NULL; + } + else + mne = "mv"; + } + else if (func == 0x3 && opaddr == 1) + mne = "seqz"; + else if (func == 0x4 && opaddr == -1) + { + mne = "not"; + op[2] = NULL; + } + else + { + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64, opaddr); + op[2] = addrbuf; + + if (func == 0x0 && rs1 == 0 && rd != 0) + { + op[1] = op[2]; + op[2] = NULL; + mne = "li"; + } + } + if (mne != NULL && idx == 0x06) + { + mne = strcpy (mnebuf, mne); + strcat (mnebuf, "w"); + } + break; + case 0x05: + case 0x0d: + // LUI and AUIPC + mne = idx == 0x05 ? "auipc" : "lui"; + op[0] = REG ((word >> 7) & 0x1f); + opaddr = word >> 12; + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr); + op[1] = addrbuf; + break; + case 0x08: + case 0x09: + // STORE and STORE-FP + rs2 = (word >> 20) & 0x1f; + op[0] = idx == 0x08 ? REG (rs2) : FREG (rs2); + opaddr = ((((int64_t) ((int32_t) word) >> 20)) & ~0x1f) | ((word >> 7) & 0x1f); + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", + opaddr, REG ((word >> 15) & 0x1f)); + op[1] = addrbuf; + func = (word >> 12) & 0x7; + static const char *const storemne[8] = + { + "sb", "sh", "sw", "sd", NULL, NULL, NULL, NULL + }; + static const char *const fstoremne[8] = + { + NULL, NULL, "fsw", "fsd", "fsq", NULL, NULL, NULL + }; + mne = (char *) (idx == 0x08 ? storemne[func] : fstoremne[func]); + break; + case 0x0b: + // AMO + op[0] = REG ((word >> 7) & 0x1f); + rs1 = (word >> 15) & 0x1f; + rs2 = (word >> 20) & 0x1f; + snprintf (addrbuf, sizeof (addrbuf), "(%s)", REG (rs1)); + op[2] = addrbuf; + size_t width = (word >> 12) & 0x7; + func = word >> 27; + static const char *const amomne[32] = + { + "amoadd", "amoswap", "lr", "sc", "amoxor", NULL, NULL, NULL, + "amoor", NULL, NULL, NULL, "amoand", NULL, NULL, NULL, + "amomin", NULL, NULL, NULL, "amomax", NULL, NULL, NULL, + "amominu", NULL, NULL, NULL, "amomaxu", NULL, NULL, NULL + }; + if (amomne[func] != NULL && width >= 2 && width <= 3 + && (func != 0x02 || rs2 == 0)) + { + if (func == 0x02) + { + op[1] = op[2]; + op[2] = NULL; + } + else + op[1] = REG (rs2); + + char *cp = stpcpy (mnebuf, amomne[func]); + *cp++ = '.'; + *cp++ = " wd "[width]; + assert (cp[-1] != ' '); + static const char *const aqrlstr[4] = + { + "", ".rl", ".aq", ".aqrl" + }; + strcpy (cp, aqrlstr[(word >> 25) & 0x3]); + mne = mnebuf; + } + break; + case 0x0c: + case 0x0e: + // OP and OP-32 + if ((word & 0xbc000000) == 0) + { + rs1 = (word >> 15) & 0x1f; + rs2 = (word >> 20) & 0x1f; + op[0] = REG ((word >> 7) & 0x1f); + func = ((word >> 21) & 0x10) | ((word >> 27) & 0x8) | ((word >> 12) & 0x7); + static const char *const arithmne2[32] = + { + "add", "sll", "slt", "sltu", "xor", "srl", "or", "and", + "sub", NULL, NULL, NULL, NULL, "sra", NULL, NULL, + "mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; + static const char *const arithmne3[32] = + { + "addw", "sllw", NULL, NULL, NULL, "srlw", NULL, NULL, + "subw", NULL, NULL, NULL, NULL, "sraw", NULL, NULL, + "mulw", NULL, NULL, NULL, "divw", "divuw", "remw", "remuw", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; + if (func == 8 && rs1 == 0) + { + mne = idx == 0x0c ? "neg" : "negw"; + op[1] = REG (rs2); + } + else if (idx == 0x0c && rs2 == 0 && func == 2) + { + op[1] = REG (rs1); + mne = "sltz"; + } + else if (idx == 0x0c && rs1 == 0 && (func == 2 || func == 3)) + { + op[1] = REG (rs2); + mne = func == 2 ? "sgtz" : "snez"; + } + else + { + mne = (char *) (idx == 0x0c ? arithmne2[func] : arithmne3[func]); + op[1] = REG (rs1); + op[2] = REG (rs2); + } + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + // MADD, MSUB, NMSUB, NMADD + if ((word & 0x06000000) != 0x04000000) + { + rd = (word >> 7) & 0x1f; + rs1 = (word >> 15) & 0x1f; + rs2 = (word >> 20) & 0x1f; + rs3 = (word >> 27) & 0x1f; + uint32_t rm = (word >> 12) & 0x7; + width = (word >> 25) & 0x3; + + static const char *const fmamne[4] = + { + "fmadd.", "fmsub.", "fnmsub.", "fnmadd." + }; + char *cp = stpcpy (mnebuf, fmamne[idx & 0x3]); + *cp++ = widthchar[width]; + *cp = '\0'; + mne = mnebuf; + op[0] = FREG (rd); + op[1] = FREG (rs1); + op[2] = FREG (rs2); + op[3] = FREG (rs3); + if (rm != 0x7) + op[4] = (char *) rndmode[rm]; + } + break; + case 0x14: + // OP-FP + if ((word & 0x06000000) != 0x04000000) + { + width = (word >> 25) & 0x3; + rd = (word >> 7) & 0x1f; + rs1 = (word >> 15) & 0x1f; + rs2 = (word >> 20) & 0x1f; + func = word >> 27; + uint32_t rm = (word >> 12) & 0x7; + if (func < 4) + { + static const char *const fpop[4] = + { + "fadd", "fsub", "fmul", "fdiv" + }; + char *cp = stpcpy (mnebuf, fpop[func]); + *cp++ = '.'; + *cp++ = widthchar[width]; + *cp = '\0'; + mne = mnebuf; + op[0] = FREG (rd); + op[1] = FREG (rs1); + op[2] = FREG (rs2); + if (rm != 0x7) + op[3] = (char *) rndmode[rm]; + } + else if (func == 0x1c && width != 2 && rs2 == 0 && rm <= 1) + { + char *cp; + if (rm == 0) + { + cp = stpcpy (mnebuf, "fmv.x."); + *cp++ = intwidthchar[width]; + } + else + { + cp = stpcpy (mnebuf, "fclass."); + *cp++ = widthchar[width]; + } + *cp = '\0'; + mne = mnebuf; + op[0] = REG (rd); + op[1] = FREG (rs1); + } + else if (func == 0x1e && width != 2 && rs2 == 0 && rm == 0) + { + char *cp = stpcpy (mnebuf, "fmv."); + *cp++ = intwidthchar[width]; + strcpy (cp, ".x"); + mne = mnebuf; + op[0] = FREG (rd); + op[1] = REG (rs1); + } + else if (func == 0x14) + { + uint32_t cmpop = (word >> 12) & 0x7; + if (cmpop < 3) + { + static const char *const mnefpcmp[3] = + { + "fle", "flt", "feq" + }; + char *cp = stpcpy (mnebuf, mnefpcmp[cmpop]); + *cp++ = '.'; + *cp++ = widthchar[width]; + *cp = '\0'; + mne = mnebuf; + op[0] = REG (rd); + op[1] = FREG (rs1); + op[2] = FREG (rs2); + } + } + else if (func == 0x04) + { + uint32_t cmpop = (word >> 12) & 0x7; + if (cmpop < 3) + { + op[0] = FREG (rd); + op[1] = FREG (rs1); + + static const char *const mnefpcmp[3] = + { + "fsgnj.", "fsgnjn.", "fsgnjx." + }; + static const char *const altsignmne[3] = + { + "fmv.", "fneg.", "fabs." + }; + char *cp = stpcpy (mnebuf, rs1 == rs2 ? altsignmne[cmpop] : mnefpcmp[cmpop]); + *cp++ = widthchar[width]; + *cp = '\0'; + mne = mnebuf; + + if (rs1 != rs2) + op[2] = FREG (rs2); + } + } + else if (func == 0x08 && width != 2 && rs2 <= 3 && rs2 != 2 && rs2 != width) + { + op[0] = FREG (rd); + op[1] = FREG (rs1); + char *cp = stpcpy (mnebuf, "fcvt."); + *cp++ = widthchar[width]; + *cp++ = '.'; + *cp++ = widthchar[rs2]; + *cp = '\0'; + mne = mnebuf; + } + else if ((func & 0x1d) == 0x18 && width != 2 && rs2 < 4) + { + char *cp = stpcpy (mnebuf, "fcvt."); + if (func == 0x18) + { + *cp++ = rs2 >= 2 ? 'l' : 'w'; + if ((rs2 & 1) == 1) + *cp++ = 'u'; + *cp++ = '.'; + *cp++ = widthchar[width]; + *cp = '\0'; + op[0] = REG (rd); + op[1] = FREG (rs1); + } + else + { + *cp++ = widthchar[width]; + *cp++ = '.'; + *cp++ = rs2 >= 2 ? 'l' : 'w'; + if ((rs2 & 1) == 1) + *cp++ = 'u'; + *cp = '\0'; + op[0] = FREG (rd); + op[1] = REG (rs1); + } + mne = mnebuf; + if (rm != 0x7 && (func == 0x18 || width == 0 || rs2 >= 2)) + op[2] = (char *) rndmode[rm]; + } + else if (func == 0x0b && rs2 == 0) + { + op[0] = FREG (rd); + op[1] = FREG (rs1); + char *cp = stpcpy (mnebuf, "fsqrt."); + *cp++ = widthchar[width]; + *cp = '\0'; + mne = mnebuf; + if (rm != 0x7) + op[2] = (char *) rndmode[rm]; + } + else if (func == 0x05 && rm < 2) + { + op[0] = FREG (rd); + op[1] = FREG (rs1); + op[2] = FREG (rs2); + char *cp = stpcpy (mnebuf, rm == 0 ? "fmin." : "fmax."); + *cp++ = widthchar[width]; + *cp = '\0'; + mne = mnebuf; + } + else if (func == 0x14 && rm <= 0x2) + { + op[0] = REG (rd); + op[1] = FREG (rs1); + op[2] = FREG (rs2); + static const char *const fltcmpmne[3] = + { + "fle.", "flt.", "feq." + }; + char *cp = stpcpy (mnebuf, fltcmpmne[rm]); + *cp++ = widthchar[width]; + *cp = '\0'; + mne = mnebuf; + } + } + break; + case 0x18: + // BRANCH + rs1 = (word >> 15) & 0x1f; + op[0] = REG (rs1); + rs2 = (word >> 20) & 0x1f; + op[1] = REG (rs2); + opaddr = addr + (((UINT64_C (0) - (word >> 31)) << 12) + + ((word << 4) & 0x800) + + ((word >> 20) & 0x7e0) + + ((word >> 7) & 0x1e)); + // TODO translate address + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr); + op[2] = addrbuf; + static const char *const branchmne[8] = + { + "beq", "bne", NULL, NULL, "blt", "bge", "bltu", "bgeu" + }; + func = (word >> 12) & 0x7; + mne = (char *) branchmne[func]; + if (rs1 == 0 && func == 5) + { + op[0] = op[1]; + op[1] = op[2]; + op[2] = NULL; + mne = "blez"; + } + else if (rs1 == 0 && func == 4) + { + op[0] = op[1]; + op[1] = op[2]; + op[2] = NULL; + mne = "bgtz"; + } + else if (rs2 == 0) + { + if (func == 0 || func == 1 || func == 4 || func == 5) + { + op[1] = op[2]; + op[2] = NULL; + strcpy (stpcpy (mnebuf, mne), "z"); + mne = mnebuf; + } + } + else if (func == 5 || func == 7) + { + // binutils use these opcodes and the reverse parameter order + char *tmp = op[0]; + op[0] = op[1]; + op[1] = tmp; + mne = func == 5 ? "ble" : "bleu"; + } + break; + case 0x19: + // JALR + if ((word & 0x7000) == 0) + { + rd = (word >> 7) & 0x1f; + rs1 = (word >> 15) & 0x1f; + opaddr = (int32_t) word >> 20; + size_t next = 0; + if (rd > 1) + op[next++] = REG (rd); + if (opaddr == 0) + { + if (rs1 != 0 || next == 0) + op[next] = REG (rs1); + } + else + { + snprintf (addrbuf, sizeof (addrbuf), "%" PRId64 "(%s)", opaddr, REG (rs1)); + op[next] = addrbuf; + } + mne = rd == 0 ? "jr" : "jalr"; + } + break; + case 0x1b: + // JAL + rd = (word >> 7) & 0x1f; + if (rd != 0) + op[0] = REG (rd); + opaddr = addr + ((UINT64_C (0) - ((word >> 11) & 0x100000)) + | (word & 0xff000) + | ((word >> 9) & 0x800) + | ((word >> 20) & 0x7fe)); + // TODO translate address + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx64, opaddr); + op[rd != 0] = addrbuf; + mne = rd == 0 ? "j" : "jal"; + break; + case 0x1c: + // SYSTEM + rd = (word >> 7) & 0x1f; + rs1 = (word >> 15) & 0x1f; + if (word == 0x00000073) + mne = "ecall"; + else if (word == 0x00100073) + mne = "ebreak"; + else if (word == 0x00200073) + mne = "uret"; + else if (word == 0x10200073) + mne = "sret"; + else if (word == 0x30200073) + mne = "mret"; + else if (word == 0x10500073) + mne = "wfi"; + else if ((word & 0x3000) == 0x2000 && rs1 == 0) + { + uint32_t csr = word >> 20; + if (/* csr >= 0x000 && */ csr <= 0x007) + { + static const char *const unprivrw[4] = + { + NULL, "frflags", "frrm", "frsr", + }; + mne = (char *) unprivrw[csr - 0x000]; + } + else if (csr >= 0xc00 && csr <= 0xc03) + { + static const char *const unprivrolow[3] = + { + "rdcycle", "rdtime", "rdinstret" + }; + mne = (char *) unprivrolow[csr - 0xc00]; + } + op[0] = REG ((word >> 7) & 0x1f); + } + else if ((word & 0x3000) == 0x1000 && rd == 0) + { + uint32_t csr = word >> 20; + if (/* csr >= 0x000 && */ csr <= 0x003) + { + static const char *const unprivrs[4] = + { + NULL, "fsflags", "fsrm", "fssr", + }; + static const char *const unprivrsi[4] = + { + NULL, "fsflagsi", "fsrmi", NULL + }; + mne = (char *) ((word & 0x4000) == 0 ? unprivrs : unprivrsi)[csr - 0x000]; + + if ((word & 0x4000) == 0) + op[0] = REG ((word >> 15) & 0x1f); + else + { + snprintf (immbuf, sizeof (immbuf), "%" PRIu32, (word >> 15) & 0x1f); + op[0] = immbuf; + } + } + } + if (mne == NULL && (word & 0x3000) != 0) + { + static const char *const mnecsr[8] = + { + NULL, "csrrw", "csrrs", "csrrc", + NULL, "csrrwi", "csrrsi", "csrrci" + }; + static const struct known_csrs known[] = + { + // This list must remain sorted by NR. + { 0x000, "ustatus" }, + { 0x001, "fflags" }, + { 0x002, "fram" }, + { 0x003, "fcsr" }, + { 0x004, "uie" }, + { 0x005, "utvec" }, + { 0x040, "uscratch" }, + { 0x041, "uepc" }, + { 0x042, "ucause" }, + { 0x043, "utval" }, + { 0x044, "uip" }, + { 0x100, "sstatus" }, + { 0x102, "sedeleg" }, + { 0x103, "sideleg" }, + { 0x104, "sie" }, + { 0x105, "stvec" }, + { 0x106, "scounteren" }, + { 0x140, "sscratch" }, + { 0x141, "sepc" }, + { 0x142, "scause" }, + { 0x143, "stval" }, + { 0x144, "sip" }, + { 0x180, "satp" }, + { 0x200, "vsstatus" }, + { 0x204, "vsie" }, + { 0x205, "vstvec" }, + { 0x240, "vsscratch" }, + { 0x241, "vsepc" }, + { 0x242, "vscause" }, + { 0x243, "vstval" }, + { 0x244, "vsip" }, + { 0x280, "vsatp" }, + { 0x600, "hstatus" }, + { 0x602, "hedeleg" }, + { 0x603, "hideleg" }, + { 0x605, "htimedelta" }, + { 0x606, "hcounteren" }, + { 0x615, "htimedeltah" }, + { 0x680, "hgatp" }, + { 0xc00, "cycle" }, + { 0xc01, "time" }, + { 0xc02, "instret" }, + { 0xc03, "hpmcounter3" }, + { 0xc04, "hpmcounter4" }, + { 0xc05, "hpmcounter5" }, + { 0xc06, "hpmcounter6" }, + { 0xc07, "hpmcounter7" }, + { 0xc08, "hpmcounter8" }, + { 0xc09, "hpmcounter9" }, + { 0xc0a, "hpmcounter10" }, + { 0xc0b, "hpmcounter11" }, + { 0xc0c, "hpmcounter12" }, + { 0xc0d, "hpmcounter13" }, + { 0xc0e, "hpmcounter14" }, + { 0xc0f, "hpmcounter15" }, + { 0xc10, "hpmcounter16" }, + { 0xc11, "hpmcounter17" }, + { 0xc12, "hpmcounter18" }, + { 0xc13, "hpmcounter19" }, + { 0xc14, "hpmcounter20" }, + { 0xc15, "hpmcounter21" }, + { 0xc16, "hpmcounter22" }, + { 0xc17, "hpmcounter23" }, + { 0xc18, "hpmcounter24" }, + { 0xc19, "hpmcounter25" }, + { 0xc1a, "hpmcounter26" }, + { 0xc1b, "hpmcounter27" }, + { 0xc1c, "hpmcounter28" }, + { 0xc1d, "hpmcounter29" }, + { 0xc1e, "hpmcounter30" }, + { 0xc1f, "hpmcounter31" }, + { 0xc80, "cycleh" }, + { 0xc81, "timeh" }, + { 0xc82, "instreth" }, + { 0xc83, "hpmcounter3h" }, + { 0xc84, "hpmcounter4h" }, + { 0xc85, "hpmcounter5h" }, + { 0xc86, "hpmcounter6h" }, + { 0xc87, "hpmcounter7h" }, + { 0xc88, "hpmcounter8h" }, + { 0xc89, "hpmcounter9h" }, + { 0xc8a, "hpmcounter10h" }, + { 0xc8b, "hpmcounter11h" }, + { 0xc8c, "hpmcounter12h" }, + { 0xc8d, "hpmcounter13h" }, + { 0xc8e, "hpmcounter14h" }, + { 0xc8f, "hpmcounter15h" }, + { 0xc90, "hpmcounter16h" }, + { 0xc91, "hpmcounter17h" }, + { 0xc92, "hpmcounter18h" }, + { 0xc93, "hpmcounter19h" }, + { 0xc94, "hpmcounter20h" }, + { 0xc95, "hpmcounter21h" }, + { 0xc96, "hpmcounter22h" }, + { 0xc97, "hpmcounter23h" }, + { 0xc98, "hpmcounter24h" }, + { 0xc99, "hpmcounter25h" }, + { 0xc9a, "hpmcounter26h" }, + { 0xc9b, "hpmcounter27h" }, + { 0xc9c, "hpmcounter28h" }, + { 0xc9d, "hpmcounter29h" }, + { 0xc9e, "hpmcounter30h" }, + { 0xc9f, "hpmcounter31h" }, + }; + uint32_t csr = word >> 20; + uint32_t instr = (word >> 12) & 0x7; + size_t last = 0; + if (rd != 0) + op[last++] = REG (rd); + struct known_csrs key = { csr, NULL }; + struct known_csrs *found = bsearch (&key, known, + sizeof (known) / sizeof (known[0]), + sizeof (known[0]), + compare_csr); + if (found) + op[last] = (char *) found->name; + else + { + snprintf (addrbuf, sizeof (addrbuf), "0x%" PRIx32, csr); + op[last] = addrbuf; + } + ++last; + if ((word & 0x4000) == 0) + op[last] = REG ((word >> 15) & 0x1f); + else + { + snprintf (immbuf, sizeof (immbuf), "%" PRIu32, (word >> 15) & UINT32_C(0x1f)); + op[last] = immbuf; + } + if (instr == 1 && rd == 0) + mne = "csrw"; + else if (instr == 2 && rd == 0) + mne = "csrs"; + else if (instr == 6 && rd == 0) + mne = "csrsi"; + else if (instr == 2 && rs1 == 0) + mne = "csrr"; + else if (instr == 3 && rd == 0) + mne = "csrc"; + else + mne = (char *) mnecsr[instr]; + } + break; + default: + break; + } + + if (strp == NULL && mne == NULL) + { + len = snprintf (addrbuf, sizeof (addrbuf), "0x%08" PRIx32, word); + strp = addrbuf; + } + } + else + { + // No instruction encodings defined for these sizes yet. + char *cp = stpcpy (mnebuf, "0x"); + assert (length % 2 == 0); + for (size_t i = 0; i < length; i += 2) + cp += snprintf (cp, mnebuf + sizeof (mnebuf) - cp, "%04" PRIx16, + read_2ubyte_unaligned (data + i)); + strp = mnebuf; + len = cp - mnebuf; + } + + if (strp == NULL) + { + + if (0) + { + /* Resize the buffer. */ + char *oldbuf; + enomem: + oldbuf = buf; + if (buf == initbuf) + buf = malloc (2 * bufsize); + else + buf = realloc (buf, 2 * bufsize); + if (buf == NULL) + { + buf = oldbuf; + retval = ENOMEM; + goto do_ret; + } + bufsize *= 2; + + bufcnt = 0; + } + + unsigned long string_end_idx = 0; + fmt = save_fmt; + const char *deferred_start = NULL; + size_t deferred_len = 0; + // XXX Can we get this from color.c? + static const char color_off[] = "\e[0m"; + while (*fmt != '\0') + { + if (*fmt != '%') + { + char ch = *fmt++; + if (ch == '\\') + { + switch ((ch = *fmt++)) + { + case '0' ... '7': + { + int val = ch - '0'; + ch = *fmt; + if (ch >= '0' && ch <= '7') + { + val *= 8; + val += ch - '0'; + ch = *++fmt; + if (ch >= '0' && ch <= '7' && val < 32) + { + val *= 8; + val += ch - '0'; + ++fmt; + } + } + ch = val; + } + break; + + case 'n': + ch = '\n'; + break; + + case 't': + ch = '\t'; + break; + + default: + retval = EINVAL; + goto do_ret; + } + } + else if (ch == '\e' && *fmt == '[') + { + deferred_start = fmt - 1; + do + ++fmt; + while (*fmt != 'm' && *fmt != '\0'); + + if (*fmt == 'm') + { + deferred_len = ++fmt - deferred_start; + continue; + } + + fmt = deferred_start + 1; + deferred_start = NULL; + } + ADD_CHAR (ch); + continue; + } + ++fmt; + + int width = 0; + while (isdigit (*fmt)) + width = width * 10 + (*fmt++ - '0'); + + int prec = 0; + if (*fmt == '.') + while (isdigit (*++fmt)) + prec = prec * 10 + (*fmt - '0'); + + size_t start_idx = bufcnt; + size_t non_printing = 0; + switch (*fmt++) + { + case 'm': + if (deferred_start != NULL) + { + ADD_NSTRING (deferred_start, deferred_len); + non_printing += deferred_len; + } + + ADD_STRING (mne); + + if (deferred_start != NULL) + { + ADD_STRING (color_off); + non_printing += strlen (color_off); + } + + string_end_idx = bufcnt; + break; + + case 'o': + if (op[prec - 1] != NULL) + { + if (deferred_start != NULL) + { + ADD_NSTRING (deferred_start, deferred_len); + non_printing += deferred_len; + } + + ADD_STRING (op[prec - 1]); + + if (deferred_start != NULL) + { + ADD_STRING (color_off); + non_printing += strlen (color_off); + } + + string_end_idx = bufcnt; + } + else + bufcnt = string_end_idx; + break; + + case 'e': + string_end_idx = bufcnt; + break; + + case 'a': + /* Pad to requested column. */ + while (bufcnt - non_printing < (size_t) width) + ADD_CHAR (' '); + width = 0; + break; + + case 'l': + // TODO + break; + + default: + abort(); + } + + /* Pad according to the specified width. */ + while (bufcnt - non_printing < start_idx + width) + ADD_CHAR (' '); + } + + strp = buf; + len = bufcnt; + } + + addr += length; + *startp = data + length; + retval = outcb (strp, len, outcbarg); + if (retval != 0) + break; + } + + do_ret: + if (buf != initbuf) + free (buf); + + return retval; +} diff --git a/src/objdump.c b/src/objdump.c index 6b365d5c..a619674f 100644 --- a/src/objdump.c +++ b/src/objdump.c @@ -717,11 +717,13 @@ show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx) info.address_color = color_address; info.bytes_color = color_bytes; - if (asprintf (&fmt, "%s%%7m %s%%.1o,%s%%.2o,%s%%.3o%%34a %s%%l", + if (asprintf (&fmt, "%s%%7m %s%%.1o,%s%%.2o,%s%%.3o,,%s%%.4o%s%%.5o%%34a %s%%l", color_mnemonic ?: "", color_operand1 ?: "", color_operand2 ?: "", color_operand3 ?: "", + color_operand4 ?: "", + color_operand5 ?: "", color_label ?: "") < 0) error (EXIT_FAILURE, errno, _("cannot allocate memory")); } @@ -729,7 +731,7 @@ show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx) { info.address_color = info.bytes_color = NULL; - fmt = "%7m %.1o,%.2o,%.3o%34a %l"; + fmt = "%7m %.1o,%.2o,%.3o,%.4o,%.5o%34a %l"; } disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr, diff --git a/tests/Makefile.am b/tests/Makefile.am index f12e48f8..d87d9616 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -165,7 +165,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-strip-version.sh run-xlate-note.sh \ run-readelf-discr.sh \ run-dwelf_elf_e_machine_string.sh \ - run-elfclassify.sh run-elfclassify-self.sh + run-elfclassify.sh run-elfclassify-self.sh \ + run-disasm-riscv64.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 diff --git a/tests/run-disasm-riscv64.sh b/tests/run-disasm-riscv64.sh new file mode 100755 index 00000000..5353e818 --- /dev/null +++ b/tests/run-disasm-riscv64.sh @@ -0,0 +1,529 @@ +#! /bin/sh +# Copyright (C) 2019 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. $srcdir/test-subr.sh + +testfiles testfile-riscv64-dis1.o testfile-riscv64-dis1.expect +testrun_compare ${abs_top_builddir}/src/objdump -d testfile-riscv64-dis1.o < testfile-riscv64-dis1.expect + +exit $? + +# The following code is used to generate the test file. +cat <<EOF | riscv64-linux-gnu-as -c -o testfile-riscv64-dis1.o - +.text +.word 0x80000037 +.word 0x800000b7 +.word 0x40300137 +.word 0x90000017 +.word 0x01003317 +.word 0x000000ef +.word 0x0000116f +.word 0x000021ef +.word 0x0000426f +.word 0x000082ef +.word 0x0001036f +.word 0x000203ef +.word 0x0004046f +.word 0x000804ef +.word 0x0010056f +.word 0x002005ef +.word 0x0040066f +.word 0x008006ef +.word 0x0100076f +.word 0x020007ef +.word 0x0400086f +.word 0x080008ef +.word 0x1000096f +.word 0x200009ef +.word 0x40000a6f +.word 0x80000aef +.word 0x00000067 +.word 0x80008567 +.word 0x050109e7 +.word 0x00d30863 +.word 0x80c41463 +.word 0x40d348e3 +.word 0x20d35263 +.word 0x10d364e3 +.word 0x08d37463 +.word 0x00000003 +.word 0x83050703 +.word 0x00001003 +.word 0x850c1383 +.word 0x04012003 +.word 0xa50c2383 +.word 0x05013003 +.word 0xf50c3383 +.word 0x00004003 +.word 0x83054703 +.word 0x00005003 +.word 0x850c5383 +.word 0x04016003 +.word 0xa50c6383 +.word 0x00000023 +.word 0x5f430323 +.word 0x00001023 +.word 0x5f431323 +.word 0x00002023 +.word 0x5f432323 +.word 0x00003023 +.word 0x5f433323 +.word 0x00000013 +.word 0x00000093 +.word 0x00300093 +.word 0x00310093 +.word 0x00002013 +.word 0x00002093 +.word 0x00302093 +.word 0x00312093 +.word 0x00003013 +.word 0x00003093 +.word 0x00303093 +.word 0x00313093 +.word 0x00004013 +.word 0x00004093 +.word 0x00304093 +.word 0x00314093 +.word 0x00006013 +.word 0x00006093 +.word 0x00306093 +.word 0x00316093 +.word 0x00007013 +.word 0x00007093 +.word 0x00307093 +.word 0x00317093 +.word 0x00311093 +.word 0x00315093 +.word 0x40315093 +.word 0x00000033 +.word 0x010000b3 +.word 0x40000033 +.word 0x410000b3 +.word 0x40010033 +.word 0x410200b3 +.word 0x00001033 +.word 0x010010b3 +.word 0x00002033 +.word 0x010020b3 +.word 0x00012033 +.word 0x010220b3 +.word 0x00003033 +.word 0x010030b3 +.word 0x00043033 +.word 0x010530b3 +.word 0x00004033 +.word 0x010040b3 +.word 0x00005033 +.word 0x010050b3 +.word 0x40005033 +.word 0x410050b3 +.word 0x00006033 +.word 0x010060b3 +.word 0x00007033 +.word 0x010070b3 +.word 0x0000000f +.word 0x0210000f +.word 0x00000073 +.word 0x00100073 +.word 0x0000001b +.word 0x0010001b +.word 0x0000101b +.word 0x0010101b +.word 0x0000501b +.word 0x0000501b +.word 0x4010501b +.word 0x4010501b +.word 0x0000003b +.word 0x0000003b +.word 0x00d0833b +.word 0x00d0833b +.word 0x40d0833b +.word 0x40d0833b +.word 0x00d0933b +.word 0x00d0933b +.word 0x00d0d33b +.word 0x00d0d33b +.word 0x40d0d33b +.word 0x40d0d33b +.word 0x0000100f +.word 0x00431073 +.word 0x00431ff3 +.word 0xc0132ff3 +.word 0xc8133ff3 +.word 0x00435ff3 +.word 0xc0136ff3 +.word 0xc8137ff3 +.word 0x02000033 +.word 0x02e40733 +.word 0x02001033 +.word 0x02e41733 +.word 0x02002033 +.word 0x02e42733 +.word 0x02003033 +.word 0x02e43733 +.word 0x02004033 +.word 0x02e44733 +.word 0x02005033 +.word 0x02e45733 +.word 0x02006033 +.word 0x02e46733 +.word 0x02007033 +.word 0x02e47733 +.word 0x0200003b +.word 0x02e4073b +.word 0x0200403b +.word 0x02e4473b +.word 0x0200503b +.word 0x02e4573b +.word 0x0200603b +.word 0x02e4673b +.word 0x0200703b +.word 0x02e4773b +.word 0x1000202f +.word 0x1800202f +.word 0x1000302f +.word 0x1800302f +.word 0x0800202f +.word 0x0800302f +.word 0x0000202f +.word 0x0000302f +.word 0x2000202f +.word 0x2000302f +.word 0x6000202f +.word 0x6000302f +.word 0x4000202f +.word 0x4000302f +.word 0x8000202f +.word 0x8000302f +.word 0xa000202f +.word 0xa000302f +.word 0xc000202f +.word 0xc000302f +.word 0xe000202f +.word 0xe000302f +.word 0x00002007 +.word 0x00003007 +.word 0x00004007 +.word 0x00002027 +.word 0x00003027 +.word 0x00004027 +.word 0x00002043 +.word 0x02002043 +.word 0x06002043 +.word 0x00002047 +.word 0x02002047 +.word 0x06002047 +.word 0x0000204b +.word 0x0200204b +.word 0x0600204b +.word 0x0000204f +.word 0x0200204f +.word 0x0600204f +.word 0x00000053 +.word 0x00001053 +.word 0x00002053 +.word 0x00003053 +.word 0x00004053 +.word 0x00007053 +.word 0x02000053 +.word 0x06000053 +.word 0x08000053 +.word 0x0a000053 +.word 0x0e000053 +.word 0x10000053 +.word 0x12000053 +.word 0x16000053 +.word 0x18000053 +.word 0x1a000053 +.word 0x1e000053 +.word 0x58000053 +.word 0x5a000053 +.word 0x5e000053 +.word 0x20000053 +.word 0x20300053 +.word 0x22000053 +.word 0x22300053 +.word 0x26000053 +.word 0x26300053 +.word 0x20001053 +.word 0x20401053 +.word 0x22001053 +.word 0x22401053 +.word 0x26001053 +.word 0x26401053 +.word 0x20002053 +.word 0x20702053 +.word 0x22002053 +.word 0x22702053 +.word 0x26002053 +.word 0x26702053 +.word 0x29700053 +.word 0x2b700053 +.word 0x2f700053 +.word 0x29701053 +.word 0x2b701053 +.word 0x2f701053 +.word 0xc00332d3 +.word 0xc02332d3 +.word 0xc20342d3 +.word 0xc22342d3 +.word 0xc60222d3 +.word 0xc62222d3 +.word 0xc01332d3 +.word 0xc03332d3 +.word 0xc21342d3 +.word 0xc23342d3 +.word 0xc61222d3 +.word 0xc63222d3 +.word 0xe00503d3 +.word 0xe20504d3 +.word 0xe60509d3 +.word 0xa0340753 +.word 0xa0341753 +.word 0xa0342753 +.word 0xa2340753 +.word 0xa2341753 +.word 0xa2342753 +.word 0xa6340753 +.word 0xa6341753 +.word 0xa6342753 +.word 0xe0091d53 +.word 0xe2091d53 +.word 0xe6091d53 +.word 0xd00e2453 +.word 0xd02e2453 +.word 0xd01e1453 +.word 0xd03e1453 +.word 0xd2030553 +.word 0xd2130553 +.word 0xd6030553 +.word 0xd6130553 +.word 0xd22e2453 +.word 0xd23e1453 +.word 0xd62e2453 +.word 0xd63e2453 +.word 0xf00c0753 +.word 0xf20c0753 +.word 0xf60c0753 +.short 0x1000 +.short 0x0800 +.short 0x0400 +.short 0x0200 +.short 0x0100 +.short 0x0080 +.short 0x0040 +.short 0x0020 +.short 0x3100 +.short 0x2900 +.short 0x2500 +.short 0x2140 +.short 0x2120 +.short 0x5100 +.short 0x4900 +.short 0x4500 +.short 0x4140 +.short 0x4120 +.short 0x7100 +.short 0x6900 +.short 0x6500 +.short 0x6140 +.short 0x6120 +.short 0xb100 +.short 0xa900 +.short 0xa500 +.short 0xa140 +.short 0xa120 +.short 0xd100 +.short 0xc900 +.short 0xc500 +.short 0xc140 +.short 0xc120 +.short 0xf100 +.short 0xe900 +.short 0xe500 +.short 0xe140 +.short 0xe120 +.short 0x1001 +.short 0x1301 +.short 0x0341 +.short 0x0321 +.short 0x0311 +.short 0x0309 +.short 0x0305 +.short 0x2081 +.short 0x3081 +.short 0x20c1 +.short 0x20a1 +.short 0x2091 +.short 0x2089 +.short 0x2085 +.short 0x2105 +.short 0x2185 +.short 0x2205 +.short 0x2285 +.short 0x2305 +.short 0x2385 +.short 0x2405 +.short 0x2485 +.short 0x2505 +.short 0x2585 +.short 0x2605 +.short 0x2685 +.short 0x2705 +.short 0x2785 +.short 0x2805 +.short 0x2885 +.short 0x2905 +.short 0x2985 +.short 0x2a05 +.short 0x2a85 +.short 0x2b05 +.short 0x2b85 +.short 0x2c05 +.short 0x2c85 +.short 0x2d05 +.short 0x2d85 +.short 0x2e05 +.short 0x2e85 +.short 0x2f05 +.short 0x2f85 +.short 0x4081 +.short 0x5081 +.short 0x40c1 +.short 0x40a1 +.short 0x4091 +.short 0x4089 +.short 0x4085 +.short 0x7101 +.short 0x6141 +.short 0x6121 +.short 0x6111 +.short 0x6109 +.short 0x6105 +.short 0x7301 +.short 0x6341 +.short 0x6321 +.short 0x6311 +.short 0x6309 +.short 0x6305 +.short 0x9001 +.short 0x8041 +.short 0x8021 +.short 0x8011 +.short 0x8009 +.short 0x8005 +.short 0x8405 +.short 0x8801 +.short 0x9801 +.short 0x8941 +.short 0x8921 +.short 0x8911 +.short 0x8909 +.short 0x8905 +.short 0x8f11 +.short 0x8f31 +.short 0x8f51 +.short 0x8f71 +.short 0x9f11 +.short 0x9f31 +.short 0xa001 +.short 0xb001 +.short 0xa801 +.short 0xa401 +.short 0xa201 +.short 0xa101 +.short 0xa081 +.short 0xa041 +.short 0xa021 +.short 0xa011 +.short 0xa009 +.short 0xa005 +.short 0xc301 +.short 0xd301 +.short 0xcb01 +.short 0xc701 +.short 0xc341 +.short 0xc321 +.short 0xc311 +.short 0xc309 +.short 0xc305 +.short 0xe301 +.short 0xf301 +.short 0xeb01 +.short 0xe701 +.short 0xe341 +.short 0xe321 +.short 0xe311 +.short 0xe309 +.short 0xe305 +.short 0x1302 +.short 0x0342 +.short 0x0322 +.short 0x0312 +.short 0x030a +.short 0x0306 +.short 0x2702 +.short 0x3702 +.short 0x2742 +.short 0x2722 +.short 0x2712 +.short 0x270a +.short 0x2706 +.short 0x4702 +.short 0x5702 +.short 0x4742 +.short 0x4722 +.short 0x4712 +.short 0x470a +.short 0x4706 +.short 0x6702 +.short 0x7702 +.short 0x6742 +.short 0x6722 +.short 0x6712 +.short 0x670a +.short 0x6706 +.short 0x8302 +.short 0x8342 +.short 0x9002 +.short 0x9502 +.short 0x9572 +.short 0xa062 +.short 0xb062 +.short 0xa862 +.short 0xa462 +.short 0xa262 +.short 0xa162 +.short 0xa0e2 +.short 0xc062 +.short 0xd062 +.short 0xc862 +.short 0xc462 +.short 0xc262 +.short 0xc162 +.short 0xc0e2 +.short 0xe062 +.short 0xf062 +.short 0xe862 +.short 0xe462 +.short 0xe262 +.short 0xe162 +.short 0xe0e2 +.word 0x00153073 +.word 0x0011d073 +.word 0x0011e073 +EOF diff --git a/tests/testfile-riscv64-dis1.expect.bz2 b/tests/testfile-riscv64-dis1.expect.bz2 new file mode 100644 index 00000000..2740795d Binary files /dev/null and b/tests/testfile-riscv64-dis1.expect.bz2 differ diff --git a/tests/testfile-riscv64-dis1.o.bz2 b/tests/testfile-riscv64-dis1.o.bz2 new file mode 100644 index 00000000..50f95f26 Binary files /dev/null and b/tests/testfile-riscv64-dis1.o.bz2 differ diff --git a/tests/testfile45.expect.bz2 b/tests/testfile45.expect.bz2 index b8b33e9b..e502e15a 100644 Binary files a/tests/testfile45.expect.bz2 and b/tests/testfile45.expect.bz2 differ
signature.asc
Description: OpenPGP digital signature