Rizin
unix-like reverse engineering framework and cli tools
cc.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2021 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2011-2021 Oddcoder <ahmedsoliman@oddcoder.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 /* Universal calling convention implementation based on sdb */
6 
7 #include <rz_analysis.h>
8 #define DB analysis->sdb_cc
9 
10 RZ_API void rz_analysis_cc_del(RzAnalysis *analysis, const char *name) {
11  rz_return_if_fail(analysis && name);
12  size_t i;
13  RzStrBuf sb;
14  sdb_unset(DB, rz_strbuf_initf(&sb, "%s", name), 0);
15  sdb_unset(DB, rz_strbuf_setf(&sb, "cc.%s.ret", name), 0);
16  sdb_unset(DB, rz_strbuf_setf(&sb, "cc.%s.argn", name), 0);
17  for (i = 0; i < RZ_ANALYSIS_CC_MAXARG; i++) {
18  sdb_unset(DB, rz_strbuf_setf(&sb, "cc.%s.arg%zu", name, i), 0);
19  }
20  sdb_unset(DB, rz_strbuf_setf(&sb, "cc.%s.self", name), 0);
21  sdb_unset(DB, rz_strbuf_setf(&sb, "cc.%s.error", name), 0);
23 }
24 
25 RZ_API bool rz_analysis_cc_set(RzAnalysis *analysis, const char *expr) {
26  rz_return_val_if_fail(analysis && expr, false);
27  char *e = strdup(expr);
28  char *p = strchr(e, '(');
29  if (!p) {
30  free(e);
31  return false;
32  }
33  *p++ = 0;
34  char *args = strdup(p);
35  rz_str_trim(p);
36  char *end = strchr(args, ')');
37  if (!end) {
38  free(args);
39  free(e);
40  return false;
41  }
42  *end++ = 0;
43  rz_str_trim(p);
44  rz_str_trim(e);
45  char *ccname = strchr(e, ' ');
46  if (ccname) {
47  *ccname++ = 0;
48  rz_str_trim(ccname);
49  } else {
50  free(args);
51  free(e);
52  return false;
53  }
54  sdb_set(DB, ccname, "cc", 0);
55  sdb_set(DB, sdb_fmt("cc.%s.ret", ccname), e, 0);
56 
57  RzList *ccArgs = rz_str_split_list(args, ",", 0);
59  const char *arg;
60  int n = 0;
61  rz_list_foreach (ccArgs, iter, arg) {
62  if (!strcmp(arg, "stack")) {
63  sdb_set(DB, sdb_fmt("cc.%s.argn", ccname), arg, 0);
64  } else {
65  sdb_set(DB, sdb_fmt("cc.%s.arg%d", ccname, n), arg, 0);
66  n++;
67  }
68  }
69  rz_list_free(ccArgs);
70  free(e);
71  free(args);
72  return true;
73 }
74 
75 RZ_API char *rz_analysis_cc_get(RzAnalysis *analysis, const char *name) {
76  rz_return_val_if_fail(analysis && name, NULL);
77  int i;
78  // get cc by name and print the expr
79  if (rz_str_cmp(sdb_const_get(DB, name, 0), "cc", -1)) {
80  RZ_LOG_ERROR("'%s' is not a valid calling convention name\n", name);
81  return NULL;
82  }
83  const char *ret = sdb_const_get(DB, sdb_fmt("cc.%s.ret", name), 0);
84  if (!ret) {
85  RZ_LOG_ERROR("Cannot find return key in calling convention named '%s'\n", name);
86  return NULL;
87  }
89  const char *self = rz_analysis_cc_self(analysis, name);
90  rz_strbuf_appendf(sb, "%s %s%s%s (", ret, self ? self : "", self ? "." : "", name);
91  bool isFirst = true;
92  for (i = 0; i < RZ_ANALYSIS_CC_MAXARG; i++) {
93  const char *k = sdb_fmt("cc.%s.arg%d", name, i);
94  const char *arg = sdb_const_get(DB, k, 0);
95  if (!arg) {
96  break;
97  }
98  rz_strbuf_appendf(sb, "%s%s", isFirst ? "" : ", ", arg);
99  isFirst = false;
100  }
101  const char *argn = sdb_const_get(DB, sdb_fmt("cc.%s.argn", name), 0);
102  if (argn) {
103  rz_strbuf_appendf(sb, "%s%s", isFirst ? "" : ", ", argn);
104  }
105  rz_strbuf_append(sb, ")");
106 
107  const char *error = rz_analysis_cc_error(analysis, name);
108  if (error) {
109  rz_strbuf_appendf(sb, " %s", error);
110  }
111 
112  rz_strbuf_append(sb, ";");
113  return rz_strbuf_drain(sb);
114 }
115 
116 RZ_API bool rz_analysis_cc_exist(RzAnalysis *analysis, const char *convention) {
117  rz_return_val_if_fail(analysis && convention, false);
118  const char *x = sdb_const_get(DB, convention, 0);
119  return x && *x && !strcmp(x, "cc");
120 }
121 
122 RZ_API const char *rz_analysis_cc_arg(RzAnalysis *analysis, const char *convention, int n) {
123  rz_return_val_if_fail(analysis, NULL);
125  if (!convention) {
126  return NULL;
127  }
128 
129  const char *query = sdb_fmt("cc.%s.arg%d", convention, n);
130  const char *ret = sdb_const_get(DB, query, 0);
131  if (!ret) {
132  query = sdb_fmt("cc.%s.argn", convention);
133  ret = sdb_const_get(DB, query, 0);
134  }
135  return ret ? rz_str_constpool_get(&analysis->constpool, ret) : NULL;
136 }
137 
138 RZ_API const char *rz_analysis_cc_self(RzAnalysis *analysis, const char *convention) {
139  rz_return_val_if_fail(analysis && convention, NULL);
140  const char *query = sdb_fmt("cc.%s.self", convention);
141  const char *self = sdb_const_get(DB, query, 0);
142  return self ? rz_str_constpool_get(&analysis->constpool, self) : NULL;
143 }
144 
145 RZ_API void rz_analysis_cc_set_self(RzAnalysis *analysis, const char *convention, const char *self) {
146  rz_return_if_fail(analysis && convention && self);
147  if (!rz_analysis_cc_exist(analysis, convention)) {
148  return;
149  }
150  RzStrBuf sb;
151  sdb_set(analysis->sdb_cc, rz_strbuf_initf(&sb, "cc.%s.self", convention), self, 0);
152  rz_strbuf_fini(&sb);
153 }
154 
155 RZ_API const char *rz_analysis_cc_error(RzAnalysis *analysis, const char *convention) {
156  rz_return_val_if_fail(analysis && convention, NULL);
157  const char *query = sdb_fmt("cc.%s.error", convention);
158  const char *error = sdb_const_get(DB, query, 0);
159  return error ? rz_str_constpool_get(&analysis->constpool, error) : NULL;
160 }
161 
162 RZ_API void rz_analysis_cc_set_error(RzAnalysis *analysis, const char *convention, const char *error) {
163  if (!rz_analysis_cc_exist(analysis, convention)) {
164  return;
165  }
166  RzStrBuf sb;
167  sdb_set(analysis->sdb_cc, rz_strbuf_initf(&sb, "cc.%s.error", convention), error, 0);
168  rz_strbuf_fini(&sb);
169 }
170 
171 RZ_API int rz_analysis_cc_max_arg(RzAnalysis *analysis, const char *cc) {
172  int i = 0;
173  rz_return_val_if_fail(analysis && DB && cc, 0);
174  static void *oldDB = NULL;
175  static char *oldCC = NULL;
176  static int oldArg = 0;
177  if (oldDB == DB && !strcmp(cc, oldCC)) {
178  return oldArg;
179  }
180  oldDB = DB;
181  free(oldCC);
182  oldCC = strdup(cc);
183  for (i = 0; i < RZ_ANALYSIS_CC_MAXARG; i++) {
184  const char *query = sdb_fmt("cc.%s.arg%d", cc, i);
185  const char *res = sdb_const_get(DB, query, 0);
186  if (!res) {
187  break;
188  }
189  }
190  oldArg = i;
191  return i;
192 }
193 
194 RZ_API const char *rz_analysis_cc_ret(RzAnalysis *analysis, const char *convention) {
195  rz_return_val_if_fail(analysis && convention, NULL);
196  char *query = sdb_fmt("cc.%s.ret", convention);
197  return sdb_const_get(DB, query, 0);
198 }
199 
200 RZ_API const char *rz_analysis_cc_default(RzAnalysis *analysis) {
201  rz_return_val_if_fail(analysis, NULL);
202  return sdb_const_get(DB, "default.cc", 0);
203 }
204 
205 RZ_API void rz_analysis_set_cc_default(RzAnalysis *analysis, const char *cc) {
206  rz_return_if_fail(analysis && cc);
207  sdb_set(DB, "default.cc", cc, 0);
208 }
209 
211  rz_return_val_if_fail(analysis, NULL);
212  return sdb_const_get(DB, "default.syscc", 0);
213 }
214 
215 RZ_API void rz_analysis_set_syscc_default(RzAnalysis *analysis, const char *cc) {
216  rz_return_if_fail(analysis && cc);
217  sdb_set(DB, "default.syscc", cc, 0);
218 }
219 
220 RZ_API const char *rz_analysis_cc_func(RzAnalysis *analysis, const char *func_name) {
221  rz_return_val_if_fail(analysis && func_name, NULL);
222  const char *cc = rz_type_func_cc(analysis->typedb, func_name);
223  return cc ? cc : rz_analysis_cc_default(analysis);
224 }
225 
227  RzList *ccl = rz_list_new();
228  SdbKv *kv;
229  SdbListIter *iter;
230  SdbList *l = sdb_foreach_list(analysis->sdb_cc, true);
231  ls_foreach (l, iter, kv) {
232  if (!strcmp(sdbkv_value(kv), "cc")) {
233  rz_list_append(ccl, strdup(sdbkv_key(kv)));
234  }
235  }
236  ls_free(l);
237  return ccl;
238 }
#define e(frag)
lzma_index ** i
Definition: index.h:629
static const char * arg(RzAnalysis *a, csh *handle, cs_insn *insn, char *buf, int n)
Definition: arm_esil32.c:136
static SblHeader sb
Definition: bin_mbn.c:26
static RzNumCalcValue expr(RzNum *, RzNumCalc *, int)
Definition: calc.c:167
RZ_API const char * rz_analysis_syscc_default(RzAnalysis *analysis)
Definition: cc.c:210
RZ_API void rz_analysis_set_syscc_default(RzAnalysis *analysis, const char *cc)
Definition: cc.c:215
RZ_API const char * rz_analysis_cc_func(RzAnalysis *analysis, const char *func_name)
Definition: cc.c:220
RZ_API void rz_analysis_cc_del(RzAnalysis *analysis, const char *name)
Definition: cc.c:10
RZ_API char * rz_analysis_cc_get(RzAnalysis *analysis, const char *name)
Definition: cc.c:75
RZ_API bool rz_analysis_cc_set(RzAnalysis *analysis, const char *expr)
Definition: cc.c:25
RZ_API void rz_analysis_cc_set_error(RzAnalysis *analysis, const char *convention, const char *error)
Definition: cc.c:162
RZ_API const char * rz_analysis_cc_arg(RzAnalysis *analysis, const char *convention, int n)
Definition: cc.c:122
RZ_API bool rz_analysis_cc_exist(RzAnalysis *analysis, const char *convention)
Definition: cc.c:116
RZ_API void rz_analysis_cc_set_self(RzAnalysis *analysis, const char *convention, const char *self)
Definition: cc.c:145
RZ_API const char * rz_analysis_cc_self(RzAnalysis *analysis, const char *convention)
Definition: cc.c:138
#define DB
Definition: cc.c:8
RZ_API const char * rz_analysis_cc_default(RzAnalysis *analysis)
Definition: cc.c:200
RZ_API int rz_analysis_cc_max_arg(RzAnalysis *analysis, const char *cc)
Definition: cc.c:171
RZ_API const char * rz_analysis_cc_error(RzAnalysis *analysis, const char *convention)
Definition: cc.c:155
RZ_API RzList * rz_analysis_calling_conventions(RzAnalysis *analysis)
Definition: cc.c:226
RZ_API const char * rz_analysis_cc_ret(RzAnalysis *analysis, const char *convention)
Definition: cc.c:194
RZ_API void rz_analysis_set_cc_default(RzAnalysis *analysis, const char *cc)
Definition: cc.c:205
#define RZ_API
#define NULL
Definition: cris-opc.c:27
const char * k
Definition: dsignal.c:11
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
void * p
Definition: libc.cpp:67
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
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_API void ls_free(SdbList *list)
Definition: ls.c:191
#define ls_foreach(list, it, pos)
Definition: ls.h:31
int args
Definition: mipsasm.c:18
int x
Definition: mipsasm.c:20
int n
Definition: mipsasm.c:19
#define RZ_ANALYSIS_CC_MAXARG
Definition: rz_analysis.h:189
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str)
Removes whitespace characters (space, tab, newline etc.) from the beginning and end of a string.
Definition: str_trim.c:190
RZ_API int rz_str_cmp(const char *dst, const char *orig, int len)
Definition: str.c:974
RZ_API RzList * rz_str_split_list(char *str, const char *c, int n)
Split the string str according to the substring c and returns a RzList with the result.
Definition: str.c:3429
RZ_API const char * rz_str_constpool_get(RzStrConstPool *pool, const char *str)
Definition: str_constpool.c:19
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 const char * rz_strbuf_initf(RzStrBuf *sb, const char *fmt,...)
Definition: strbuf.c:38
RZ_API const char * rz_strbuf_setf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API void rz_strbuf_fini(RzStrBuf *sb)
Definition: strbuf.c:365
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
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611
RZ_API const char * sdb_const_get(Sdb *s, const char *key, ut32 *cas)
Definition: sdb.c:279
RZ_API int sdb_unset(Sdb *s, const char *key, ut32 cas)
Definition: sdb.c:294
RZ_API SdbList * sdb_foreach_list(Sdb *s, bool sorted)
Definition: sdb.c:630
static char * sdbkv_key(const SdbKv *kv)
Definition: sdbht.h:21
static char * sdbkv_value(const SdbKv *kv)
Definition: sdbht.h:25
Definition: ls.h:17
Definition: ls.h:22
Definition: z80asm.h:102
RzStrConstPool constpool
Definition: rz_analysis.h:620
RzTypeDB * typedb
Definition: rz_analysis.h:602
Definition: sdbht.h:14
RZ_API RZ_BORROW const char * rz_type_func_cc(RzTypeDB *typedb, RZ_NONNULL const char *name)
Searches for the RzCallable type in types database and returns calling convention.
Definition: function.c:230
void error(const char *msg)
Definition: untgz.c:593