Rizin
unix-like reverse engineering framework and cli tools
disassembler.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2022 Dhruv Maroo <dhruvmaru007@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "disassembler.h"
5 #include "common.h"
6 #include "regs.h"
7 
8 extern const SHOpRaw sh_op_lookup[];
9 extern const ut32 OPCODE_NUM;
10 
19  if (shb.is_param) {
20  return shb.param;
21  }
22  if (shb.addr.mode == SH_ADDR_INVALID) {
23  SHParam invalid;
24  invalid.mode = SH_ADDR_INVALID;
25  return invalid;
26  }
27 
28  ut16 nibble = opcode >> shb.addr.start;
29  ut8 len = 0;
30 
31  if (shb.addr.bits != -1) {
32  // do not infer the bit length from mode
33  len = shb.addr.bits;
34  goto extract;
35  }
36 
37  switch (shb.addr.mode) {
38  case SH_REG_DIRECT:
39  case SH_REG_INDIRECT:
40  case SH_REG_INDIRECT_I:
41  case SH_REG_INDIRECT_D:
43  case SH_PC_RELATIVE_REG:
44  len = 4;
45  break;
49  case SH_PC_RELATIVE8:
50  case SH_IMM_S:
51  case SH_IMM_U:
52  len = 8;
53  break;
54  case SH_PC_RELATIVE12:
55  len = 12;
56  break;
57  default:
58  break;
59  }
60 
61 extract:
62 
63  nibble &= 0xffff >> (16 - len);
64 
65  SHParam ret_param;
66  ret_param.mode = shb.addr.mode;
67  switch (shb.addr.mode) {
68  case SH_REG_DIRECT:
69  case SH_REG_INDIRECT:
70  case SH_REG_INDIRECT_I:
71  case SH_REG_INDIRECT_D:
75  case SH_PC_RELATIVE8:
76  case SH_PC_RELATIVE12:
77  case SH_PC_RELATIVE_REG:
78  case SH_IMM_S:
79  case SH_IMM_U:
80  ret_param.param[0] = nibble;
81  break;
83  ret_param.param[0] = nibble >> 4;
84  ret_param.param[1] = nibble & 0xf;
85  break;
87  break;
88  default:
89  break;
90  }
91 
92  /* For the special case of banked registers in `LDC` and `STC`, the bit length is 3
93  In such case, we can modify the param found to correspond to its banked counterpart */
94  if (len == 3) {
95  ret_param.param[0] += SH_REG_IND_R0B;
96  }
97 
98  return ret_param;
99 }
100 
110 static SHParam sh_op_get_param_movl(ut16 opcode, bool m) {
111  if (m) {
112  ut16 reg = (opcode >> 4) & 0xf;
113  return (SHParam){ .param = {
114  reg,
115  },
116  .mode = SH_REG_DIRECT };
117  } else {
118  ut16 d = opcode & 0xf;
119  ut16 n = (opcode >> 8) & 0xf;
120  return (SHParam){ .param = { n, d }, .mode = SH_REG_INDIRECT_DISP };
121  }
122 }
123 
131  for (ut16 i = 0; i < OPCODE_NUM; i++) {
132  if ((opcode | sh_op_lookup[i].mask) != sh_op_lookup[i].opcode) {
133  continue;
134  }
135 
136  SHOpRaw raw = sh_op_lookup[i];
137  SHOp *op = RZ_NEW(SHOp);
138  op->opcode = opcode;
139  op->mnemonic = raw.mnemonic;
140  op->scaling = raw.scaling;
141  op->str_mnem = raw.str_mnem;
142  // check for "weird" mov.l
143  if (raw.opcode == MOVL) {
144  op->param[0] = sh_op_get_param_movl(opcode, true);
145  op->param[1] = sh_op_get_param_movl(opcode, false);
146  return op;
147  }
148  op->param[0] = sh_op_get_param(opcode, raw.param_builder[0]);
149  op->param[1] = sh_op_get_param(opcode, raw.param_builder[1]);
150  return op;
151  }
152 
153  RZ_LOG_DEBUG("SuperH: Invalid opcode encountered by disassembler: 0x%06x\n", opcode);
154  return NULL;
155 }
156 
157 #undef MOVL
158 
167  if (param.mode == SH_ADDR_INVALID) {
168  return NULL;
169  }
170 
172  switch (param.mode) {
173  case SH_REG_DIRECT:
174  rz_strbuf_appendf(buf, "%s", sh_registers[param.param[0]]);
175  break;
176  case SH_REG_INDIRECT:
177  rz_strbuf_appendf(buf, "@%s", sh_registers[param.param[0]]);
178  break;
179  case SH_REG_INDIRECT_I:
180  rz_strbuf_appendf(buf, "@%s+", sh_registers[param.param[0]]);
181  break;
182  case SH_REG_INDIRECT_D:
183  rz_strbuf_appendf(buf, "@-%s", sh_registers[param.param[0]]);
184  break;
186  rz_strbuf_appendf(buf, "@(0x%02x,%s)", param.param[1] * sh_scaling_size[scaling], sh_registers[param.param[0]]);
187  break;
189  rz_strbuf_appendf(buf, "@(r0,%s)", sh_registers[param.param[0]]);
190  break;
192  rz_strbuf_appendf(buf, "@(0x%03x,gbr)", param.param[0] * sh_scaling_size[scaling]);
193  break;
195  rz_strbuf_append(buf, "@(r0,gbr)");
196  break;
197  case SH_PC_RELATIVE_DISP:
198  rz_strbuf_appendf(buf, "@(0x%03x,pc)", param.param[0] * sh_scaling_size[scaling]);
199  break;
200  case SH_PC_RELATIVE8:
201  case SH_PC_RELATIVE12:
202  rz_strbuf_appendf(buf, "0x%08x", (ut32)pc + 4 + (st32)((st8)param.param[0]) * 2);
203  break;
204  case SH_PC_RELATIVE_REG:
205  rz_strbuf_appendf(buf, "%s", sh_registers[param.param[0]]);
206  break;
207  case SH_IMM_U:
208  case SH_IMM_S:
209  rz_strbuf_appendf(buf, "0x%02x", param.param[0]);
210  break;
211  default:
213  }
214 
215  return rz_strbuf_drain(buf);
216 }
217 
226  if (!op->str_mnem) {
227  return NULL;
228  }
229  RzStrBuf *buf = rz_strbuf_new(op->str_mnem);
230 
231  char *param = NULL;
232  if ((param = sh_op_param_to_str(op->param[0], op->scaling, pc))) {
233  rz_strbuf_appendf(buf, " %s", param);
234  free(param);
235  if ((param = sh_op_param_to_str(op->param[1], op->scaling, pc))) {
236  rz_strbuf_appendf(buf, ", %s", param);
237  free(param);
238  }
239  }
240 
241  return rz_strbuf_drain(buf);
242 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
@ extract
Definition: aarch64.h:496
#define mask()
#define RZ_IPI
Definition: analysis_wasm.c:11
lzma_index ** i
Definition: index.h:629
#define NULL
Definition: cris-opc.c:27
uint16_t ut16
uint32_t ut32
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
#define reg(n)
uint8_t ut8
Definition: lh5801.h:11
#define MOVL
Definition: common.h:70
int n
Definition: mipsasm.c:19
static const char * sh_registers[]
Definition: regs.h:10
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define RZ_LOG_DEBUG(fmtstr,...)
Definition: rz_log.h:49
RZ_API RZ_OWN char * rz_strbuf_drain(RzStrBuf *sb)
Definition: strbuf.c:342
RZ_API bool rz_strbuf_append(RzStrBuf *sb, const char *s)
Definition: strbuf.c:222
RZ_API RzStrBuf * rz_strbuf_new(const char *s)
Definition: strbuf.c:8
RZ_API bool rz_strbuf_appendf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_NEW(x)
Definition: rz_types.h:285
#define st8
Definition: rz_types_base.h:16
#define st32
Definition: rz_types_base.h:12
RZ_IPI RZ_OWN SHOp * sh_disassembler(ut16 opcode)
Disassemble opcode and return a SHOp.
Definition: disassembler.c:130
RZ_IPI RZ_OWN char * sh_op_param_to_str(SHParam param, SHScaling scaling, ut64 pc)
Return string representation of disassembled param.
Definition: disassembler.c:166
static SHParam sh_op_get_param(ut16 opcode, SHParamBuilder shb)
Get SHParam from opcode Make sure the opcode is passed in little-endian form.
Definition: disassembler.c:18
const SHOpRaw sh_op_lookup[]
Definition: lookup.c:7
RZ_IPI RZ_OWN char * sh_op_to_str(RZ_NONNULL const SHOp *op, ut64 pc)
Return string representation of disassembled op.
Definition: disassembler.c:224
static SHParam sh_op_get_param_movl(ut16 opcode, bool m)
Get params for mov.l instruction (0001NMD) A special function is required because the nibbles for the...
Definition: disassembler.c:110
const ut32 OPCODE_NUM
Definition: lookup.c:195
enum sh_scaling_t SHScaling
static const ut8 sh_scaling_size[]
Definition: disassembler.h:43
@ SH_REG_IND_R0B
Definition: disassembler.h:139
@ SH_PC_RELATIVE8
Definition: disassembler.h:28
@ SH_IMM_S
8-bit immediate value (sign-extended)
Definition: disassembler.h:32
@ SH_REG_INDIRECT_DISP
register indirect with displacement
Definition: disassembler.h:23
@ SH_PC_RELATIVE_DISP
Definition: disassembler.h:27
@ SH_REG_DIRECT
Definition: disassembler.h:19
@ SH_PC_RELATIVE_REG
Definition: disassembler.h:30
@ SH_PC_RELATIVE12
Definition: disassembler.h:29
@ SH_REG_INDIRECT_INDEXED
indexed register indirect
Definition: disassembler.h:24
@ SH_ADDR_INVALID
Definition: disassembler.h:18
@ SH_REG_INDIRECT_I
register indirect with post-increment
Definition: disassembler.h:21
@ SH_REG_INDIRECT
Definition: disassembler.h:20
@ SH_IMM_U
8-bit immediate value (zero-extended)
Definition: disassembler.h:31
@ SH_REG_INDIRECT_D
register indirect with pre-decrement
Definition: disassembler.h:22
@ SH_GBR_INDIRECT_DISP
Definition: disassembler.h:25
@ SH_GBR_INDIRECT_INDEXED
Definition: disassembler.h:26
#define d(i)
Definition: sha256.c:44
const char * str_mnem
string mnemonic
Definition: common.h:25
SHScaling scaling
scaling for the opcode
Definition: common.h:29
SHOpMnem mnemonic
enum mnemonic
Definition: common.h:26
SHParamBuilder param_builder[2]
param builders for the params
Definition: common.h:30
ut16 opcode
opcode
Definition: common.h:27
ut8 start
start bit of the param (assuming little-endian)
Definition: common.h:10
SHAddrMode mode
addressing mode being used
Definition: common.h:12
st8 bits
bits to be read (-1, if you want this to be inferred from mode)
Definition: common.h:11
SHParam param
Definition: common.h:19
struct sh_param_builder_addr_t addr
Definition: common.h:18
bool is_param
whether a param was directly passed
Definition: common.h:21
ut16 param[2]
Definition: disassembler.h:238
SHAddrMode mode
Definition: disassembler.h:239
Definitions common to the whole liblzma library.
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()