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