Rizin
unix-like reverse engineering framework and cli tools
parse_mips_pseudo.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2012-2017 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2018-2021 deroad <wargio@libero.it>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <rz_lib.h>
10 #include <rz_util.h>
11 #include <rz_flag.h>
12 #include <rz_analysis.h>
13 #include <rz_parse.h>
14 
15 #include "parse_common.c"
16 
17 static RzList *mips_tokenize(const char *assembly, size_t length);
18 
19 static const RzPseudoGrammar mips_lexicon[] = {
20  RZ_PSEUDO_DEFINE_GRAMMAR("add", "1 = 2 + 3"),
21  RZ_PSEUDO_DEFINE_GRAMMAR("addi", "1 = 2 + 3"),
22  RZ_PSEUDO_DEFINE_GRAMMAR("addiu", "1 = 2 + 3"),
23  RZ_PSEUDO_DEFINE_GRAMMAR("addu", "1 = 2 + 3"),
24  RZ_PSEUDO_DEFINE_GRAMMAR("and", "1 = 2 & 3"),
25  RZ_PSEUDO_DEFINE_GRAMMAR("andi", "1 = 2 & 3"),
26  RZ_PSEUDO_DEFINE_GRAMMAR("b", "goto 1"),
27  RZ_PSEUDO_DEFINE_GRAMMAR("bal", "call 1"),
28  RZ_PSEUDO_DEFINE_GRAMMAR("begzal", "if (1 >= 0) call 2"),
29  RZ_PSEUDO_DEFINE_GRAMMAR("beq", "if (1 == 2) goto 3"),
30  RZ_PSEUDO_DEFINE_GRAMMAR("beqz", "if (!1) goto 2"),
31  RZ_PSEUDO_DEFINE_GRAMMAR("bgez", "if (1 >= 0) goto 2"),
32  RZ_PSEUDO_DEFINE_GRAMMAR("bgtz", "if (1 > 0) goto 2"),
33  RZ_PSEUDO_DEFINE_GRAMMAR("blez", "if (1 <= 0) goto 2"),
34  RZ_PSEUDO_DEFINE_GRAMMAR("bltz", "if (1 < 0) goto 2"),
35  RZ_PSEUDO_DEFINE_GRAMMAR("bltzal", "if (1 < 0) call 2"),
36  RZ_PSEUDO_DEFINE_GRAMMAR("bne", "if (1 != 2) goto 3"),
37  RZ_PSEUDO_DEFINE_GRAMMAR("bnez", "if (1) goto 2"),
38  RZ_PSEUDO_DEFINE_GRAMMAR("j", "goto 1"),
39  RZ_PSEUDO_DEFINE_GRAMMAR("jal", "call 1"),
40  RZ_PSEUDO_DEFINE_GRAMMAR("jalr", "call 1"),
41  RZ_PSEUDO_DEFINE_GRAMMAR("jr", "goto 1"),
42  RZ_PSEUDO_DEFINE_GRAMMAR("lb", "1 = byte [3 + 2]"),
43  RZ_PSEUDO_DEFINE_GRAMMAR("lbu", "1 = (unsigned) byte [3 + 2]"),
44  RZ_PSEUDO_DEFINE_GRAMMAR("lh", "1 = halfword [3 + 2]"),
45  RZ_PSEUDO_DEFINE_GRAMMAR("lhu", "1 = (unsigned) halfword [3 + 2]"),
46  RZ_PSEUDO_DEFINE_GRAMMAR("li", "1 = 2"),
47  RZ_PSEUDO_DEFINE_GRAMMAR("lui", "1 = 2 << #16"),
48  RZ_PSEUDO_DEFINE_GRAMMAR("lw", "1 = word [3 + 2]"),
49  RZ_PSEUDO_DEFINE_GRAMMAR("mfhi", "1 = hi"),
50  RZ_PSEUDO_DEFINE_GRAMMAR("mflo", "1 = lo"),
51  RZ_PSEUDO_DEFINE_GRAMMAR("move", "1 = 2"),
52  RZ_PSEUDO_DEFINE_GRAMMAR("movn", "if (3) 1 = 2"),
53  RZ_PSEUDO_DEFINE_GRAMMAR("movz", "if (!3) 1 = 2"),
54  RZ_PSEUDO_DEFINE_GRAMMAR("mult", "(hi,lo) = 1 * 2"),
55  RZ_PSEUDO_DEFINE_GRAMMAR("multu", "unsigned (hi,lo) = 1 * 2"),
56  RZ_PSEUDO_DEFINE_GRAMMAR("mul", "1 = 2 * 3"),
57  RZ_PSEUDO_DEFINE_GRAMMAR("mulu", "1 = 2 * 3"),
58  RZ_PSEUDO_DEFINE_GRAMMAR("negu", "1 = ~2"),
59  RZ_PSEUDO_DEFINE_GRAMMAR("nop", ""),
60  RZ_PSEUDO_DEFINE_GRAMMAR("nor", "1 = ~(2 | 3)"),
61  RZ_PSEUDO_DEFINE_GRAMMAR("or", "1 = 2 | 3"),
62  RZ_PSEUDO_DEFINE_GRAMMAR("ori", "1 = 2 | 3"),
63  RZ_PSEUDO_DEFINE_GRAMMAR("sb", "byte [3 + 2] = 1"),
64  RZ_PSEUDO_DEFINE_GRAMMAR("sh", "halfword [3 + 2] = 1"),
65  RZ_PSEUDO_DEFINE_GRAMMAR("sll", "1 = 2 << 3"),
66  RZ_PSEUDO_DEFINE_GRAMMAR("sllv", "1 = 2 << 3"),
67  RZ_PSEUDO_DEFINE_GRAMMAR("slr", "1 = 2 >> 3"),
68  RZ_PSEUDO_DEFINE_GRAMMAR("slt", "1 = (2 < 3)"),
69  RZ_PSEUDO_DEFINE_GRAMMAR("slti", "1 = (2 < 3)"),
70  RZ_PSEUDO_DEFINE_GRAMMAR("sltiu", "1 = (unsigned) (2 < 3)"),
71  RZ_PSEUDO_DEFINE_GRAMMAR("sltu", "1 = (unsigned) (2 < 3)"),
72  RZ_PSEUDO_DEFINE_GRAMMAR("sra", "1 = (signed) 2 >> 3"),
73  RZ_PSEUDO_DEFINE_GRAMMAR("srl", "1 = 2 >> 3"),
74  RZ_PSEUDO_DEFINE_GRAMMAR("srlv", "1 = 2 >> 3"),
75  RZ_PSEUDO_DEFINE_GRAMMAR("subu", "1 = 2 - 3"),
76  RZ_PSEUDO_DEFINE_GRAMMAR("sub", "1 = 2 - 3"),
77  RZ_PSEUDO_DEFINE_GRAMMAR("sw", "word [3 + 2] = 1"),
78  RZ_PSEUDO_DEFINE_GRAMMAR("syscall", "syscall"),
79  RZ_PSEUDO_DEFINE_GRAMMAR("xor", "1 = 2 ^ 3"),
80  RZ_PSEUDO_DEFINE_GRAMMAR("xori", "1 = 2 ^ 3"),
81 };
82 
83 static const RzPseudoDirect mips_direct[] = {
84  RZ_PSEUDO_DEFINE_DIRECT("jr ra", "return"),
85 };
86 
87 static const RzPseudoReplace mips_replace[] = {
88  RZ_PSEUDO_DEFINE_REPLACE(" + 0]", "]", 0),
89  RZ_PSEUDO_DEFINE_REPLACE("+ -", "- ", 1),
90  RZ_PSEUDO_DEFINE_REPLACE("0 << 16", "0", 1),
91 };
92 
94 
95 RzList *mips_tokenize(const char *assembly, size_t length) {
96  size_t i, p;
97  char *buf = NULL;
98  bool insert_zero = false;
99  RzList *tokens = NULL;
100 
101  buf = rz_str_ndup(assembly, length);
102  if (!buf) {
103  return NULL;
104  }
105 
106  for (i = 0, p = 0; p < length; ++i, ++p) {
107  if (buf[p] == ',') {
108  p++;
109  } else if (buf[p] == '(') {
110  buf[p] = ' ';
111  if (!IS_HEXCHAR(buf[p - 1])) {
112  p++;
113  insert_zero = true;
114  }
115  } else if (buf[p] == ')') {
116  buf[p] = 0;
117  } else if (buf[p] == 'z' && buf[p + 1] == 'e' && buf[p + 2] == 'r' && buf[p + 3] == 'o') {
118  p += 3;
119  buf[p] = '0';
120  }
121  if (p > i) {
122  buf[i] = buf[p];
123  }
124  }
125  buf[i] = 0;
126 
127  tokens = rz_str_split_duplist(buf, " ", true);
128  free(buf);
129  if (!tokens) {
130  return NULL;
131  }
132 
133  if (insert_zero) {
134  rz_list_insert(tokens, rz_list_length(tokens) - 1, strdup("0"));
135  }
136 
137  return tokens;
138 }
139 
140 static bool parse(RzParse *parse, const char *assembly, RzStrBuf *sb) {
141  return rz_pseudo_convert(&mips_config, assembly, sb);
142 }
143 
144 static bool subvar(RzParse *p, RzAnalysisFunction *f, RzAnalysisOp *op, char *data, char *str, int len) {
145  const ut64 addr = op->addr;
146  RzListIter *iter;
147  char *oldstr;
148  char *tstr = strdup(data);
149  RzAnalysis *analysis = p->analb.analysis;
150 
151  if (!p->varlist) {
152  free(tstr);
153  return false;
154  }
155  RzList *bpargs = p->varlist(f, 'b');
156  RzList *spargs = p->varlist(f, 's');
157  const bool ucase = IS_UPPER(*tstr);
158  RzAnalysisVarField *var;
159  rz_list_foreach (spargs, iter, var) {
160  st64 delta = p->get_ptr_at
161  ? p->get_ptr_at(f, var->delta, addr)
162  : ST64_MAX;
163  if (delta == ST64_MAX && var->field) {
164  delta = var->delta;
165  } else if (delta == ST64_MAX) {
166  continue;
167  }
168  const char *reg = NULL;
169  if (p->get_reg_at) {
170  reg = p->get_reg_at(f, var->delta, addr);
171  }
172  if (!reg) {
173  reg = analysis->reg->name[RZ_REG_NAME_SP];
174  }
175  char *tmpf;
176  // TODO: honor asm pseudo
177  if (RZ_ABS(delta) < 10) {
178  tmpf = "%d(%s)";
179  } else if (delta > 0) {
180  tmpf = "0x%x(%s)";
181  } else {
182  tmpf = "-0x%x(%s)";
183  }
184  oldstr = rz_str_newf(tmpf, RZ_ABS(delta), reg);
185  if (ucase) {
186  char *comma = strchr(oldstr, ',');
187  if (comma) {
188  *comma = 0;
189  rz_str_case(oldstr, true);
190  *comma = ',';
191  }
192  }
193  if (strstr(tstr, oldstr)) {
194  char *newstr = (p->localvar_only)
195  ? rz_str_newf("(%s)", var->name)
196  : rz_str_newf("%s%s(%s)", delta > 0 ? "" : "-", var->name, reg);
197  tstr = rz_str_replace(tstr, oldstr, newstr, 1);
198  free(newstr);
199  free(oldstr);
200  break;
201  }
202  free(oldstr);
203  }
204  rz_list_foreach (bpargs, iter, var) {
205  char *tmpf = NULL;
206  st64 delta = p->get_ptr_at
207  ? p->get_ptr_at(f, var->delta, addr)
208  : ST64_MAX;
209  if (delta == ST64_MAX && var->field) {
210  delta = var->delta + f->bp_off;
211  } else if (delta == ST64_MAX) {
212  continue;
213  }
214  const char *reg = NULL;
215  if (p->get_reg_at) {
216  reg = p->get_reg_at(f, var->delta, addr);
217  }
218  if (!reg) {
219  reg = analysis->reg->name[RZ_REG_NAME_BP];
220  }
221  if (RZ_ABS(delta) < 10) {
222  tmpf = "%d(%s)";
223  } else if (delta > 0) {
224  tmpf = "0x%x(%s)";
225  } else {
226  tmpf = "-0x%x(%s)";
227  }
228  oldstr = rz_str_newf(tmpf, RZ_ABS(delta), reg);
229  if (ucase) {
230  char *comma = strchr(oldstr, ',');
231  if (comma) {
232  *comma = 0;
233  rz_str_case(oldstr, true);
234  *comma = ',';
235  }
236  }
237  if (strstr(tstr, oldstr)) {
238  char *newstr = (p->localvar_only)
239  ? rz_str_newf("(%s)", var->name)
240  : rz_str_newf("%s%s(%s)", delta > 0 ? "" : "-", var->name, reg);
241  tstr = rz_str_replace(tstr, oldstr, newstr, 1);
242  free(newstr);
243  free(oldstr);
244  break;
245  }
246  free(oldstr);
247  }
248  bool ret = true;
249  if (len > strlen(tstr)) {
250  strcpy(str, tstr);
251  } else {
252  // TOO BIG STRING CANNOT REPLACE HERE
253  ret = false;
254  }
255  free(tstr);
256  rz_list_free(bpargs);
257  rz_list_free(spargs);
258  return ret;
259 }
260 
262  .name = "mips.pseudo",
263  .desc = "MIPS pseudo syntax",
264  .init = NULL,
265  .fini = NULL,
266  .parse = parse,
267  .subvar = subvar,
268 };
269 
270 #ifndef RZ_PLUGIN_INCORE
274  .version = RZ_VERSION
275 };
276 #endif
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static RASN1String * newstr(const char *string)
Definition: astr.c:23
static SblHeader sb
Definition: bin_mbn.c:26
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
#define reg(n)
void * p
Definition: libc.cpp:67
RZ_API RZ_BORROW RzListIter * rz_list_insert(RZ_NONNULL RzList *list, ut32 n, void *data)
Inserts a new element at the N-th position.
Definition: list.c:342
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
@ RZ_ABS
#define RZ_PSEUDO_DEFINE_REPLACE(x, y, f)
Definition: parse_common.c:64
static bool rz_pseudo_convert(const RzPseudoConfig *config, const char *assembly, RzStrBuf *sb)
Definition: parse_common.c:103
#define RZ_PSEUDO_DEFINE_DIRECT(x, y)
Definition: parse_common.c:61
#define RZ_PSEUDO_DEFINE_CONFIG(d, l, r, m, t)
Definition: parse_common.c:67
#define RZ_PSEUDO_DEFINE_GRAMMAR(x, y)
Definition: parse_common.c:58
static const RzPseudoConfig mips_config
static const RzPseudoGrammar mips_lexicon[]
static const RzPseudoDirect mips_direct[]
static bool subvar(RzParse *p, RzAnalysisFunction *f, RzAnalysisOp *op, char *data, char *str, int len)
static RzList * mips_tokenize(const char *assembly, size_t length)
RZ_API RzLibStruct rizin_plugin
RzParsePlugin rz_parse_plugin_mips_pseudo
static bool parse(RzParse *parse, const char *assembly, RzStrBuf *sb)
static const RzPseudoReplace mips_replace[]
RZ_DEPRECATE struct rz_analysis_var_field_t RzAnalysisVarField
@ RZ_LIB_TYPE_PARSE
Definition: rz_lib.h:74
@ RZ_REG_NAME_SP
Definition: rz_reg.h:44
@ RZ_REG_NAME_BP
Definition: rz_reg.h:46
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
RZ_API void rz_str_case(char *str, bool up)
Definition: str.c:341
RZ_API RzList * rz_str_split_duplist(const char *str, const char *c, bool trim)
Split the string str according to the substring c and returns a RzList with the result.
Definition: str.c:3464
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
Definition: str.c:1110
#define IS_UPPER(c)
Definition: rz_str_util.h:14
#define IS_HEXCHAR(x)
Definition: rz_str_util.h:9
#define st64
Definition: rz_types_base.h:10
#define ST64_MAX
Definition: rz_types_base.h:84
#define RZ_VERSION
Definition: rz_version.h:8
#define f(i)
Definition: sha256.c:46
Definition: regcomp.c:57
char * name[RZ_REG_NAME_LAST]
Definition: rz_reg.h:149
Definition: dis.c:32
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int comma
Definition: z80asm.c:76
static int addr
Definition: z80asm.c:58