1 /* radare - LGPL - Copyright 2011-2021 - pancake, Oddcoder */
2 
3 /* Universal calling convention implementation based on sdb */
4 
5 #include <r_anal.h>
6 #define DB anal->sdb_cc
7 
r_anal_cc_del(RAnal * anal,const char * name)8 R_API void r_anal_cc_del(RAnal *anal, const char *name) {
9 	r_return_if_fail (anal && name);
10 	size_t i;
11 	RStrBuf sb;
12 	sdb_unset (DB, r_strbuf_initf (&sb, "%s", name), 0);
13 	sdb_unset (DB, r_strbuf_setf (&sb, "cc.%s.ret", name), 0);
14 	sdb_unset (DB, r_strbuf_setf (&sb, "cc.%s.argn", name), 0);
15 	for (i = 0; i < R_ANAL_CC_MAXARG; i++) {
16 		sdb_unset (DB, r_strbuf_setf (&sb, "cc.%s.arg%zu", name, i), 0);
17 	}
18 	sdb_unset (DB, r_strbuf_setf (&sb, "cc.%s.self", name), 0);
19 	sdb_unset (DB, r_strbuf_setf (&sb, "cc.%s.error", name), 0);
20 	r_strbuf_fini (&sb);
21 }
22 
r_anal_cc_set(RAnal * anal,const char * expr)23 R_API bool r_anal_cc_set(RAnal *anal, const char *expr) {
24 	r_return_val_if_fail (anal && expr, false);
25 	char *e = strdup (expr);
26 	char *p = strchr (e, '(');
27 	if (!p) {
28 		free (e);
29 		return false;
30 	}
31 	*p++ = 0;
32 	char *args = strdup (p);
33 	r_str_trim (p);
34 	char *end = strchr (args, ')');
35 	if (!end) {
36 		free (args);
37 		free (e);
38 		return false;
39 	}
40 	*end++ = 0;
41 	r_str_trim (p);
42 	r_str_trim (e);
43 	char *ccname = strchr (e, ' ');
44 	if (ccname) {
45 		*ccname++ = 0;
46 		r_str_trim (ccname);
47 	} else {
48 		free (args);
49 		free (e);
50 		return false;
51 	}
52 	sdb_set (DB, ccname, "cc", 0);
53 	sdb_set (DB, sdb_fmt ("cc.%s.ret", ccname), e, 0);
54 
55 	RList *ccArgs = r_str_split_list (args, ",", 0);
56 	RListIter *iter;
57 	const char *arg;
58 	int n = 0;
59 	r_list_foreach (ccArgs, iter, arg) {
60 		if (!strcmp (arg, "stack")) {
61 			sdb_set (DB, sdb_fmt ("cc.%s.argn", ccname), arg, 0);
62 		} else {
63 			sdb_set (DB, sdb_fmt ("cc.%s.arg%d", ccname, n), arg, 0);
64 			n++;
65 		}
66 	}
67 	r_list_free (ccArgs);
68 	free (e);
69 	free (args);
70 	return true;
71 }
72 
r_anal_cc_once(RAnal * anal)73 R_API bool r_anal_cc_once(RAnal *anal) {
74 	return sdb_add (DB, "warn", "once", 0);
75 }
76 
r_anal_cc_get_json(RAnal * anal,PJ * pj,const char * name)77 R_API void r_anal_cc_get_json(RAnal *anal, PJ *pj, const char *name) {
78 	r_return_if_fail (anal && pj && name);
79 	int i;
80 	// get cc by name and print the expr
81 	if (r_str_cmp (sdb_const_get (DB, name, 0), "cc", -1)) {
82 		return;
83 	}
84 	const char *ret = sdb_const_get (DB, sdb_fmt ("cc.%s.ret", name), 0);
85 	if (!ret) {
86 		return;
87 	}
88 	pj_ks (pj, "ret", ret);
89 	char *sig = r_anal_cc_get (anal, name);
90 	pj_ks (pj, "signature", sig);
91 	free (sig);
92 	pj_ka (pj, "args");
93 	for (i = 0; i < R_ANAL_CC_MAXARG; i++) {
94 		const char *k = sdb_fmt ("cc.%s.arg%d", name, i);
95 		const char *arg = sdb_const_get (DB, k, 0);
96 		if (!arg) {
97 			break;
98 		}
99 		pj_s (pj, arg);
100 	}
101 	pj_end (pj);
102 	const char *argn = sdb_const_get (DB, sdb_fmt ("cc.%s.argn", name), 0);
103 	if (argn) {
104 		pj_ks (pj, "argn", argn);
105 	}
106 	const char *error = r_anal_cc_error (anal, name);
107 	if (error) {
108 		pj_ks (pj, "error", error);
109 	}
110 }
111 
r_anal_cc_get(RAnal * anal,const char * name)112 R_API char *r_anal_cc_get(RAnal *anal, const char *name) {
113 	r_return_val_if_fail (anal && name, NULL);
114 	int i;
115 	// get cc by name and print the expr
116 	if (r_str_cmp (sdb_const_get (DB, name, 0), "cc", -1)) {
117 		eprintf ("This is not a valid calling convention name\n");
118 		return NULL;
119 	}
120 	const char *ret = sdb_const_get (DB, sdb_fmt ("cc.%s.ret", name), 0);
121 	if (!ret) {
122 		eprintf ("Cannot find return key\n");
123 		return NULL;
124 	}
125 	RStrBuf *sb = r_strbuf_new (NULL);
126 	const char *self = r_anal_cc_self (anal, name);
127 	r_strbuf_appendf (sb, "%s %s%s%s (", ret, r_str_get (self), self? ".": "", name);
128 	bool isFirst = true;
129 	for (i = 0; i < R_ANAL_CC_MAXARG; i++) {
130 		const char *k = sdb_fmt ("cc.%s.arg%d", name, i);
131 		const char *arg = sdb_const_get (DB, k, 0);
132 		if (!arg) {
133 			break;
134 		}
135 		r_strbuf_appendf (sb, "%s%s", isFirst? "": ", ", arg);
136 		isFirst = false;
137 	}
138 	const char *argn = sdb_const_get (DB, sdb_fmt ("cc.%s.argn", name), 0);
139 	if (argn) {
140 		r_strbuf_appendf (sb, "%s%s", isFirst? "": ", ", argn);
141 	}
142 	r_strbuf_append (sb, ")");
143 
144 	const char *error = r_anal_cc_error (anal, name);
145 	if (error) {
146 		r_strbuf_appendf (sb, " %s", error);
147 	}
148 
149 	r_strbuf_append (sb, ";");
150 	return r_strbuf_drain (sb);
151 }
152 
r_anal_cc_exist(RAnal * anal,const char * convention)153 R_API bool r_anal_cc_exist(RAnal *anal, const char *convention) {
154 	r_return_val_if_fail (anal && convention, false);
155 	const char *x = sdb_const_get (DB, convention, 0);
156 	return x && *x && !strcmp (x, "cc");
157 }
158 
r_anal_cc_arg(RAnal * anal,const char * convention,int n)159 R_API const char *r_anal_cc_arg(RAnal *anal, const char *convention, int n) {
160 	r_return_val_if_fail (anal, NULL);
161 	r_return_val_if_fail (n >= 0, NULL);
162 	if (!convention) {
163 		return NULL;
164 	}
165 
166 	const char *query = sdb_fmt ("cc.%s.arg%d", convention, n);
167 	const char *ret = sdb_const_get (DB, query, 0);
168 	if (!ret) {
169 		query = sdb_fmt ("cc.%s.argn", convention);
170 		ret = sdb_const_get (DB, query, 0);
171 	}
172 	return ret? r_str_constpool_get (&anal->constpool, ret): NULL;
173 }
174 
r_anal_cc_self(RAnal * anal,const char * convention)175 R_API const char *r_anal_cc_self(RAnal *anal, const char *convention) {
176 	r_return_val_if_fail (anal && convention, NULL);
177 	const char *query = sdb_fmt ("cc.%s.self", convention);
178 	const char *self = sdb_const_get (DB, query, 0);
179 	return self? r_str_constpool_get (&anal->constpool, self): NULL;
180 }
181 
r_anal_cc_set_self(RAnal * anal,const char * convention,const char * self)182 R_API void r_anal_cc_set_self(RAnal *anal, const char *convention, const char *self) {
183 	r_return_if_fail (anal && convention && self);
184 	if (!r_anal_cc_exist (anal, convention)) {
185 		return;
186 	}
187 	RStrBuf sb;
188 	sdb_set (anal->sdb_cc, r_strbuf_initf (&sb, "cc.%s.self", convention), self, 0);
189 	r_strbuf_fini (&sb);
190 }
191 
r_anal_cc_error(RAnal * anal,const char * convention)192 R_API const char *r_anal_cc_error(RAnal *anal, const char *convention) {
193 	r_return_val_if_fail (anal && convention, NULL);
194 	const char *query = sdb_fmt ("cc.%s.error", convention);
195 	const char *error = sdb_const_get (DB, query, 0);
196 	return error? r_str_constpool_get (&anal->constpool, error): NULL;
197 }
198 
r_anal_cc_set_error(RAnal * anal,const char * convention,const char * error)199 R_API void r_anal_cc_set_error(RAnal *anal, const char *convention, const char *error) {
200 	r_return_if_fail (anal && convention && error);
201 	if (!r_anal_cc_exist (anal, convention)) {
202 		return;
203 	}
204 	RStrBuf sb;
205 	sdb_set (anal->sdb_cc, r_strbuf_initf (&sb, "cc.%s.error", convention), error, 0);
206 	r_strbuf_fini (&sb);
207 }
208 
r_anal_cc_max_arg(RAnal * anal,const char * cc)209 R_API int r_anal_cc_max_arg(RAnal *anal, const char *cc) {
210 	int i = 0;
211 	r_return_val_if_fail (anal && DB && cc, 0);
212 	static void *oldDB = NULL;
213 	static char *oldCC = NULL;
214 	static int oldArg = 0;
215 	if (oldDB == DB && !strcmp (cc, oldCC)) {
216 		return oldArg;
217 	}
218 	oldDB = DB;
219 	free (oldCC);
220 	oldCC = strdup (cc);
221 	for (i = 0; i < R_ANAL_CC_MAXARG; i++) {
222 		const char *query = sdb_fmt ("cc.%s.arg%d", cc, i);
223 		const char *res = sdb_const_get (DB, query, 0);
224 		if (!res) {
225 			break;
226 		}
227 	}
228 	oldArg = i;
229 	return i;
230 }
231 
r_anal_cc_ret(RAnal * anal,const char * convention)232 R_API const char *r_anal_cc_ret(RAnal *anal, const char *convention) {
233 	r_return_val_if_fail (anal && convention, NULL);
234 	char *query = sdb_fmt ("cc.%s.ret", convention);
235 	return sdb_const_get (DB, query, 0);
236 }
237 
r_anal_cc_default(RAnal * anal)238 R_API const char *r_anal_cc_default(RAnal *anal) {
239 	r_return_val_if_fail (anal, NULL);
240 	return sdb_const_get (DB, "default.cc", 0);
241 }
242 
r_anal_set_cc_default(RAnal * anal,const char * cc)243 R_API void r_anal_set_cc_default(RAnal *anal, const char *cc) {
244 	r_return_if_fail (anal && cc);
245 	sdb_set (DB, "default.cc", cc, 0);
246 }
247 
r_anal_syscc_default(RAnal * anal)248 R_API const char *r_anal_syscc_default(RAnal *anal) {
249 	r_return_val_if_fail (anal, NULL);
250 	return sdb_const_get (DB, "default.syscc", 0);
251 }
252 
r_anal_set_syscc_default(RAnal * anal,const char * cc)253 R_API void r_anal_set_syscc_default(RAnal *anal, const char *cc) {
254 	r_return_if_fail (anal && cc);
255 	sdb_set (DB, "default.syscc", cc, 0);
256 }
257 
r_anal_cc_func(RAnal * anal,const char * func_name)258 R_API const char *r_anal_cc_func(RAnal *anal, const char *func_name) {
259 	r_return_val_if_fail (anal && func_name, NULL);
260 	const char *query = sdb_fmt ("func.%s.cc", func_name);
261 	const char *cc = sdb_const_get (anal->sdb_types, query, 0);
262 	return cc ? cc : r_anal_cc_default (anal);
263 }
264