1 /* radare - Copyright 2008-2020 - LGPL -- pancake */
2 
3 #include <r_types.h>
4 #include <r_util.h>
5 #include <r_syscall.h>
6 #include <stdio.h>
7 #include <string.h>
8 
9 R_LIB_VERSION (r_syscall);
10 
11 // TODO: now we use sdb
12 extern RSyscallPort sysport_x86[];
13 extern RSyscallPort sysport_avr[];
14 
r_syscall_ref(RSyscall * sc)15 R_API RSyscall* r_syscall_ref(RSyscall *sc) {
16 	sc->refs++;
17 	return sc;
18 }
19 
r_syscall_new(void)20 R_API RSyscall* r_syscall_new(void) {
21 	RSyscall *rs = R_NEW0 (RSyscall);
22 	if (rs) {
23 		rs->sysport = sysport_x86;
24 		rs->srdb = sdb_new0 (); // sysregs database
25 		rs->db = sdb_new0 ();
26 	}
27 	return rs;
28 }
29 
r_syscall_free(RSyscall * s)30 R_API void r_syscall_free(RSyscall *s) {
31 	if (s) {
32 		if (s->refs > 0) {
33 			s->refs--;
34 			return;
35 		}
36 		sdb_free (s->srdb);
37 		sdb_free (s->db);
38 		free (s->os);
39 		free (s->cpu);
40 		free (s->arch);
41 		free (s);
42 	}
43 }
44 
openDatabase(Sdb * db,const char * name)45 static Sdb *openDatabase(Sdb *db, const char *name) {
46 	char *file = r_str_newf ( R_JOIN_3_PATHS ("%s", R2_SDB, "%s.sdb"),
47 		r_sys_prefix (NULL), name);
48 	if (r_file_exists (file)) {
49 		if (db) {
50 			sdb_reset (db);
51 			sdb_open (db, file);
52 		} else {
53 			db = sdb_new (0, file, 0);
54 		}
55 	} else {
56 		sdb_free (db);
57 		db = sdb_new0 ();
58 	}
59 	free (file);
60 	return db;
61 }
62 
syscall_reload_needed(RSyscall * s,const char * os,const char * arch,int bits)63 static inline bool syscall_reload_needed(RSyscall *s, const char *os, const char *arch, int bits) {
64 	if (!s->os || strcmp (s->os, os)) {
65 		return true;
66 	}
67 	if (!s->arch || strcmp (s->arch, arch)) {
68 		return true;
69 	}
70 	return s->bits != bits;
71 }
72 
sysregs_reload_needed(RSyscall * s,const char * arch,int bits,const char * cpu)73 static inline bool sysregs_reload_needed(RSyscall *s, const char *arch, int bits, const char *cpu) {
74 	if (!s->arch || strcmp (s->arch, arch)) {
75 		return true;
76 	}
77 	if (s->bits != bits) {
78 		return true;
79 	}
80 	return !s->cpu || strcmp (s->cpu, cpu);
81 }
82 
83 // TODO: should be renamed to r_syscall_use();
r_syscall_setup(RSyscall * s,const char * arch,int bits,const char * cpu,const char * os)84 R_API bool r_syscall_setup(RSyscall *s, const char *arch, int bits, const char *cpu, const char *os) {
85 	bool syscall_changed, sysregs_changed;
86 
87 	if (!os || !*os) {
88 		os = R_SYS_OS;
89 	}
90 	if (!arch) {
91 		arch = R_SYS_ARCH;
92 	}
93 	if (!cpu) {
94 		cpu = arch;
95 	}
96 	syscall_changed = syscall_reload_needed (s, os, arch, bits);
97 	sysregs_changed = sysregs_reload_needed (s, arch, bits, cpu);
98 
99 	free (s->os);
100 	s->os = strdup (os);
101 
102 	free (s->cpu);
103 	s->cpu = strdup (cpu);
104 
105 	free (s->arch);
106 	s->arch = strdup (arch);
107 
108 	s->bits = bits;
109 
110 	if (!strcmp (os, "any")) { // ignored
111 		return true;
112 	}
113 	if (!strcmp (arch, "avr")) {
114 		s->sysport = sysport_avr;
115 	} else if (!strcmp (os, "darwin") || !strcmp (os, "osx") || !strcmp (os, "macos")) {
116 		os = "darwin";
117 	} else if (!strcmp (arch, "x86")) {
118 		s->sysport = sysport_x86;
119 	}
120 
121 	if (syscall_changed) {
122 		char *dbName = r_str_newf (R_JOIN_2_PATHS ("syscall", "%s-%s-%d"),
123 			os, arch, bits);
124 		if (dbName) {
125 			s->db = openDatabase (s->db, dbName);
126 			free (dbName);
127 		}
128 	}
129 
130 	if (sysregs_changed) {
131 		char *dbName = r_str_newf (R_JOIN_2_PATHS ("sysregs", "%s-%d-%s"),
132 			arch, bits, cpu);
133 		if (dbName) {
134 			sdb_free (s->srdb);
135 			s->srdb = openDatabase (NULL, dbName);
136 			free (dbName);
137 		}
138 	}
139 	if (s->fd) {
140 		fclose (s->fd);
141 		s->fd = NULL;
142 	}
143 	return true;
144 }
145 
r_syscall_item_new_from_string(const char * name,const char * s)146 R_API RSyscallItem *r_syscall_item_new_from_string(const char *name, const char *s) {
147 	RSyscallItem *si;
148 	char *o;
149 	if (!name || !s) {
150 		return NULL;
151 	}
152 	o = strdup (s);
153 	int cols = r_str_split (o, ',');
154 	if (cols < 3) {
155 		free (o);
156 		return NULL;
157 	}
158 
159 	si = R_NEW0 (RSyscallItem);
160 	if (!si) {
161 		free (o);
162 		return NULL;
163 	}
164 	si->name = strdup (name);
165 	si->swi = (int)r_num_get (NULL, r_str_word_get0 (o, 0));
166 	si->num = (int)r_num_get (NULL, r_str_word_get0 (o, 1));
167 	si->args = (int)r_num_get (NULL, r_str_word_get0 (o, 2));
168 	si->sargs = calloc (si->args + 1, sizeof (char));
169 	if (!si->sargs) {
170 		free (si);
171 		free (o);
172 		return NULL;
173 	}
174 	if (cols > 3) {
175 		strncpy (si->sargs, r_str_word_get0 (o, 3), si->args);
176 	}
177 	free (o);
178 	return si;
179 }
180 
r_syscall_item_free(RSyscallItem * si)181 R_API void r_syscall_item_free(RSyscallItem *si) {
182 	if (!si) {
183 		return;
184 	}
185 	free (si->name);
186 	free (si->sargs);
187 	free (si);
188 }
189 
getswi(RSyscall * s,int swi)190 static int getswi(RSyscall *s, int swi) {
191 	if (s && swi == -1) {
192 		return r_syscall_get_swi (s);
193 	}
194 	return swi;
195 }
196 
r_syscall_get_swi(RSyscall * s)197 R_API int r_syscall_get_swi(RSyscall *s) {
198 	return (int)sdb_num_get (s->db, "_", NULL);
199 }
200 
r_syscall_get(RSyscall * s,int num,int swi)201 R_API RSyscallItem *r_syscall_get(RSyscall *s, int num, int swi) {
202 	r_return_val_if_fail (s && s->db, NULL);
203 	const char *ret, *ret2, *key;
204 	swi = getswi (s, swi);
205 	if (swi < 16) {
206 		key = sdb_fmt ("%d.%d", swi, num);
207 	} else {
208 		key = sdb_fmt ("0x%02x.%d", swi, num);
209 	}
210 	ret = sdb_const_get (s->db, key, 0);
211 	if (!ret) {
212 		key = sdb_fmt ("0x%02x.0x%02x", swi, num); // Workaround until Syscall SDB is fixed
213 		ret = sdb_const_get (s->db, key, 0);
214 		if (!ret) {
215 			key = sdb_fmt ("0x%02x.%d", num, swi); // Workaround until Syscall SDB is fixed
216 			ret = sdb_const_get (s->db, key, 0);
217 			if (!ret) {
218 				return NULL;
219 			}
220 		}
221 	}
222 	ret2 = sdb_const_get (s->db, ret, 0);
223 	if (!ret2) {
224 		return NULL;
225 	}
226 	return r_syscall_item_new_from_string (ret, ret2);
227 }
228 
r_syscall_get_num(RSyscall * s,const char * str)229 R_API int r_syscall_get_num(RSyscall *s, const char *str) {
230 	r_return_val_if_fail (s && str && s->db, -1);
231 	int sn = (int)sdb_array_get_num (s->db, str, 1, NULL);
232 	if (sn == 0) {
233 		return (int)sdb_array_get_num (s->db, str, 0, NULL);
234 	}
235 	return sn;
236 }
237 
r_syscall_get_i(RSyscall * s,int num,int swi)238 R_API const char *r_syscall_get_i(RSyscall *s, int num, int swi) {
239 	r_return_val_if_fail (s && s->db, NULL);
240 	char foo[32];
241 	swi = getswi (s, swi);
242 	snprintf (foo, sizeof (foo), "0x%x.%d", swi, num);
243 	return sdb_const_get (s->db, foo, 0);
244 }
245 
callback_list(void * u,const char * k,const char * v)246 static bool callback_list(void *u, const char *k, const char *v) {
247 	RList *list = (RList*)u;
248 	if (!strchr (k, '.')) {
249 		RSyscallItem *si = r_syscall_item_new_from_string (k, v);
250 		if (!si) {
251 			return true;
252 		}
253 		if (!strchr (si->name, '.')) {
254 			r_list_append (list, si);
255 		} else {
256 			r_syscall_item_free (si);
257 		}
258 	}
259 	return true; // continue loop
260 }
261 
r_syscall_list(RSyscall * s)262 R_API RList *r_syscall_list(RSyscall *s) {
263 	r_return_val_if_fail (s && s->db, NULL);
264 	RList *list = r_list_newf ((RListFree)r_syscall_item_free);
265 	sdb_foreach (s->db, callback_list, list);
266 	return list;
267 }
268 
269 /* io and sysregs */
r_syscall_get_io(RSyscall * s,int ioport)270 R_API const char *r_syscall_get_io(RSyscall *s, int ioport) {
271 	r_return_val_if_fail (s, NULL);
272 	int i;
273 	const char *name = r_syscall_sysreg (s, "io", ioport);
274 	if (name) {
275 		return name;
276 	}
277 	for (i = 0; s->sysport[i].name; i++) {
278 		if (ioport == s->sysport[i].port) {
279 			return s->sysport[i].name;
280 		}
281 	}
282 	return NULL;
283 }
284 
r_syscall_sysreg(RSyscall * s,const char * type,ut64 num)285 R_API const char* r_syscall_sysreg(RSyscall *s, const char *type, ut64 num) {
286 	r_return_val_if_fail (s && s->db, NULL);
287 	const char *key = sdb_fmt ("%s,%"PFMT64d, type, num);
288 	return sdb_const_get (s->db, key, 0);
289 }
290