1 /* radare - LGPL - Copyright 2008-2021 - pancake */
2
3 #include <r_util.h>
4 #include <r_lib.h>
5
6 R_LIB_VERSION(r_lib);
7
8 /* TODO: avoid globals */
9 #define IFDBG if(__has_debug)
10 static bool __has_debug = false;
11
12 /* XXX : this must be registered in runtime */
13 static const char *r_lib_types[] = {
14 "io", "dbg", "lang", "asm", "anal", "parse", "bin", "bin_xtr", "bin_ldr",
15 "bp", "syscall", "fastcall", "crypto", "core", "egg", "fs", NULL
16 };
17
__lib_types_get(int idx)18 static const char *__lib_types_get(int idx) {
19 if (idx < 0 || idx > R_LIB_TYPE_LAST - 1) {
20 return "unk";
21 }
22 return r_lib_types[idx];
23 }
24
r_lib_types_get_i(const char * str)25 R_API int r_lib_types_get_i(const char *str) {
26 int i;
27 for (i = 0; r_lib_types[i]; i++) {
28 if (!strcmp (str, r_lib_types[i])) {
29 return i;
30 }
31 }
32 return -1;
33 }
34
r_lib_dl_open(const char * libname)35 R_API void *r_lib_dl_open(const char *libname) {
36 void *ret = NULL;
37 #if WANT_DYLINK
38 #if __UNIX__
39 if (libname) {
40 ret = dlopen (libname, RTLD_GLOBAL | RTLD_LAZY);
41 } else {
42 ret = dlopen (NULL, RTLD_NOW);
43 }
44 if (!ret && __has_debug) {
45 eprintf ("r_lib_dl_open: error: %s (%s)\n", libname, dlerror ());
46 }
47 #elif __WINDOWS__
48 LPTSTR libname_;
49 if (libname && *libname) {
50 libname_ = r_sys_conv_utf8_to_win (libname);
51 } else {
52 libname_ = calloc (MAX_PATH, sizeof (TCHAR));
53 if (!libname_) {
54 R_LOG_ERROR ("lib/r_lib_dl_open: Failed to allocate memory.\n");
55 return NULL;
56 }
57 if (!GetModuleFileName (NULL, libname_, MAX_PATH)) {
58 libname_[0] = '\0';
59 }
60 }
61 ret = LoadLibrary (libname_);
62 free (libname_);
63 if (!ret && __has_debug) {
64 eprintf ("r_lib_dl_open: error: %s\n", libname);
65 }
66 #endif
67 #endif
68 return ret;
69 }
70
r_lib_dl_sym(void * handler,const char * name)71 R_API void *r_lib_dl_sym(void *handler, const char *name) {
72 #if WANT_DYLINK
73 #if __UNIX__
74 return dlsym (handler, name);
75 #elif __WINDOWS__
76 return GetProcAddress (handler, name);
77 #else
78 return NULL;
79 #endif
80 #else
81 return NULL;
82 #endif
83 }
84
r_lib_dl_close(void * handler)85 R_API int r_lib_dl_close(void *handler) {
86 #if __UNIX__
87 return dlclose (handler);
88 #else
89 return handler? 0: -1;
90 #endif
91 }
92
r_lib_path(const char * libname)93 R_API char *r_lib_path(const char *libname) {
94 #if __WINDOWS__
95 char *tmp = r_str_newf ("%s." R_LIB_EXT, libname);
96 if (!tmp) {
97 return NULL;
98 }
99 WCHAR *name = r_utf8_to_utf16 (tmp);
100 free (tmp);
101 WCHAR *path = NULL;
102 if (!name) {
103 goto err;
104 }
105
106 int count;
107 if (!(count = SearchPathW (NULL, name, NULL, 0, NULL, NULL))) {
108 r_sys_perror ("SearchPath");
109 goto err;
110 }
111 path = malloc (count * sizeof (WCHAR));
112 if (!path) {
113 goto err;
114 }
115 if (!(count = SearchPathW (NULL, name, NULL, count, path, NULL))) {
116 R_FREE (path);
117 r_sys_perror ("SearchPath");
118 goto err;
119 }
120 tmp = r_utf16_to_utf8 (path);
121 free (name);
122 free (path);
123 return tmp;
124 err:
125 free (name);
126 return NULL;
127 #else
128 #if __APPLE__
129 char *env = r_sys_getenv ("DYLD_LIBRARY_PATH");
130 env = r_str_append (env, ":/lib:/usr/lib:/usr/local/lib");
131 #elif __UNIX__
132 char *env = r_sys_getenv ("LD_LIBRARY_PATH");
133 env = r_str_append (env, ":/lib:/usr/lib:/usr/local/lib");
134 #endif
135 if (!env) {
136 env = strdup (".");
137 }
138 char *next, *path0 = env;
139 do {
140 next = strchr (path0, ':');
141 if (next) {
142 *next = 0;
143 }
144 char *libpath = r_str_newf ("%s/%s." R_LIB_EXT, path0, libname);
145 if (r_file_exists (libpath)) {
146 free (env);
147 return libpath;
148 }
149 free (libpath);
150 path0 = next + 1;
151 } while (next);
152 free (env);
153 return NULL;
154 #endif
155 }
156
r_lib_new(const char * symname,const char * symnamefunc)157 R_API RLib *r_lib_new(const char *symname, const char *symnamefunc) {
158 RLib *lib = R_NEW (RLib);
159 if (lib) {
160 __has_debug = r_sys_getenv_asbool ("R2_DEBUG");
161 lib->handlers = r_list_newf (free);
162 lib->plugins = r_list_newf (free);
163 lib->symname = strdup (symname? symname: R_LIB_SYMNAME);
164 lib->symnamefunc = strdup (symnamefunc? symnamefunc: R_LIB_SYMFUNC);
165 }
166 return lib;
167 }
168
r_lib_free(RLib * lib)169 R_API void r_lib_free(RLib *lib) {
170 if (lib) {
171 r_lib_close (lib, NULL);
172 r_list_free (lib->handlers);
173 r_list_free (lib->plugins);
174 free (lib->symname);
175 free (lib->symnamefunc);
176 free (lib);
177 }
178 }
179
__lib_dl_check_filename(const char * file)180 static bool __lib_dl_check_filename(const char *file) {
181 return r_str_endswith (file, "." R_LIB_EXT);
182 }
183
r_lib_run_handler(RLib * lib,RLibPlugin * plugin,RLibStruct * symbol)184 R_API int r_lib_run_handler(RLib *lib, RLibPlugin *plugin, RLibStruct *symbol) {
185 RLibHandler *h = plugin->handler;
186 if (h && h->constructor) {
187 IFDBG eprintf ("PLUGIN LOADED %p fcn %p\n", h, h->constructor);
188 return h->constructor (plugin, h->user, symbol->data);
189 }
190 IFDBG eprintf ("Cannot find plugin constructor\n");
191 return -1;
192 }
193
r_lib_get_handler(RLib * lib,int type)194 R_API RLibHandler *r_lib_get_handler(RLib *lib, int type) {
195 RLibHandler *h;
196 RListIter *iter;
197 r_list_foreach (lib->handlers, iter, h) {
198 if (h->type == type) {
199 return h;
200 }
201 }
202 return NULL;
203 }
204
r_lib_close(RLib * lib,const char * file)205 R_API int r_lib_close(RLib *lib, const char *file) {
206 RLibPlugin *p;
207 RListIter *iter, *iter2;
208 r_list_foreach_safe (lib->plugins, iter, iter2, p) {
209 if ((!file || !strcmp (file, p->file))) {
210 int ret = 0;
211 if (p->handler && p->handler->destructor) {
212 ret = p->handler->destructor (p, p->handler->user, p->data);
213 }
214 if (p->free) {
215 p->free (p->data);
216 }
217 free (p->file);
218 r_list_delete (lib->plugins, iter);
219 if (file != NULL) {
220 return ret;
221 }
222 }
223 }
224 if (!file) {
225 return 0;
226 }
227 // delete similar plugin name
228 r_list_foreach (lib->plugins, iter, p) {
229 if (strstr (p->file, file)) {
230 int ret = 0;
231 if (p->handler && p->handler->destructor) {
232 ret = p->handler->destructor (p,
233 p->handler->user, p->data);
234 }
235 eprintf ("Unloaded %s\n", p->file);
236 free (p->file);
237 r_list_delete (lib->plugins, iter);
238 return ret;
239 }
240 }
241 return -1;
242 }
243
__already_loaded(RLib * lib,const char * file)244 static bool __already_loaded(RLib *lib, const char *file) {
245 const char *fileName = r_str_rstr (file, R_SYS_DIR);
246 RLibPlugin *p;
247 RListIter *iter;
248 if (fileName) {
249 r_list_foreach (lib->plugins, iter, p) {
250 const char *pFileName = r_str_rstr (p->file, R_SYS_DIR);
251 if (pFileName && !strcmp (fileName, pFileName)) {
252 return true;
253 }
254 }
255 }
256 return false;
257 }
258
r_lib_open(RLib * lib,const char * file)259 R_API int r_lib_open(RLib *lib, const char *file) {
260 /* ignored by filename */
261 if (!__lib_dl_check_filename (file)) {
262 eprintf ("Invalid library extension: %s\n", file);
263 return -1;
264 }
265
266 if (__already_loaded (lib, file)) {
267 eprintf("Not loading library because it has already been loaded from somewhere else: '%s'\n", file);
268 return -1;
269 }
270
271 void *handler = r_lib_dl_open (file);
272 if (!handler) {
273 IFDBG eprintf ("Cannot open library: '%s'\n", file);
274 return -1;
275 }
276
277 RLibStructFunc strf = (RLibStructFunc) r_lib_dl_sym (handler, lib->symnamefunc);
278 RLibStruct *stru = NULL;
279 if (strf) {
280 stru = strf ();
281 }
282 if (!stru) {
283 stru = (RLibStruct *) r_lib_dl_sym (handler, lib->symname);
284 }
285 if (!stru) {
286 IFDBG eprintf ("Cannot find symbol '%s' in library '%s'\n",
287 lib->symname, file);
288 r_lib_dl_close (handler);
289 return -1;
290 }
291
292 int res = r_lib_open_ptr (lib, file, handler, stru);
293 if (strf) {
294 free (stru);
295 }
296 return res;
297 }
298
major_minor(const char * s)299 static char *major_minor(const char *s) {
300 char *a = strdup (s);
301 char *p = strchr (a, '.');
302 if (p) {
303 p = strchr (p + 1, '.');
304 if (p) {
305 *p = 0;
306 }
307 }
308 return a;
309 }
310
r_lib_open_ptr(RLib * lib,const char * file,void * handler,RLibStruct * stru)311 R_API int r_lib_open_ptr(RLib *lib, const char *file, void *handler, RLibStruct *stru) {
312 r_return_val_if_fail (lib && file && stru, -1);
313 if (stru->version) {
314 char *mm0 = major_minor (stru->version);
315 char *mm1 = major_minor (R2_VERSION);
316 bool mismatch = strcmp (mm0, mm1);
317 free (mm0);
318 free (mm1);
319 if (mismatch) {
320 eprintf ("Module version mismatch %s (%s) vs (%s)\n",
321 file, stru->version, R2_VERSION);
322 if (stru->pkgname) {
323 const char *dot = strchr (stru->version, '.');
324 int major = atoi (stru->version);
325 int minor = dot ? atoi (dot + 1) : 0;
326 // The pkgname member was introduced in 4.2.0
327 if (major > 4 || (major == 4 && minor >= 2)) {
328 printf ("r2pm -ci %s\n", stru->pkgname);
329 }
330 }
331 return -1;
332 }
333 }
334 RLibPlugin *p = R_NEW0 (RLibPlugin);
335 p->type = stru->type;
336 p->data = stru->data;
337 p->file = strdup (file);
338 p->dl_handler = handler;
339 p->handler = r_lib_get_handler (lib, p->type);
340 p->free = stru->free;
341
342 int ret = r_lib_run_handler (lib, p, stru);
343 if (ret == -1) {
344 IFDBG eprintf ("Library handler has failed for '%s'\n", file);
345 free (p->file);
346 free (p);
347 r_lib_dl_close (handler);
348 } else {
349 r_list_append (lib->plugins, p);
350 }
351
352 return ret;
353 }
354
r_lib_opendir(RLib * lib,const char * path)355 R_API bool r_lib_opendir(RLib *lib, const char *path) {
356 #if WANT_DYLINK
357 r_return_val_if_fail (lib && path, false);
358 #if __WINDOWS__
359 wchar_t file[1024];
360 WIN32_FIND_DATAW dir;
361 HANDLE fh;
362 wchar_t directory[MAX_PATH];
363 wchar_t *wcpath;
364 char *wctocbuff;
365 #else
366 char file[1024];
367 struct dirent *de;
368 DIR *dh;
369 #endif
370 #ifdef R2_LIBR_PLUGINS
371 if (!path) {
372 path = R2_LIBR_PLUGINS;
373 }
374 #endif
375 if (!path) {
376 return false;
377 }
378 #if __WINDOWS__
379 wcpath = r_utf8_to_utf16 (path);
380 if (!wcpath) {
381 return false;
382
383 }
384 swprintf (directory, _countof (directory), L"%ls\\*.*", wcpath);
385 fh = FindFirstFileW (directory, &dir);
386 if (fh == INVALID_HANDLE_VALUE) {
387 IFDBG eprintf ("Cannot open directory %ls\n", wcpath);
388 free (wcpath);
389 return false;
390 }
391 do {
392 swprintf (file, _countof (file), L"%ls/%ls", wcpath, dir.cFileName);
393 wctocbuff = r_utf16_to_utf8 (file);
394 if (wctocbuff) {
395 if (__lib_dl_check_filename (wctocbuff)) {
396 r_lib_open (lib, wctocbuff);
397 } else {
398 IFDBG eprintf ("Cannot open %ls\n", dir.cFileName);
399 }
400 free (wctocbuff);
401 }
402 } while (FindNextFileW (fh, &dir));
403 FindClose (fh);
404 free (wcpath);
405 #else
406 dh = opendir (path);
407 if (!dh) {
408 IFDBG eprintf ("Cannot open directory '%s'\n", path);
409 return false;
410 }
411 while ((de = (struct dirent *)readdir (dh))) {
412 if (de->d_name[0] == '.' || strstr (de->d_name, ".dSYM")) {
413 continue;
414 }
415 snprintf (file, sizeof (file), "%s/%s", path, de->d_name);
416 if (__lib_dl_check_filename (file)) {
417 IFDBG eprintf ("Loading %s\n", file);
418 r_lib_open (lib, file);
419 } else {
420 IFDBG eprintf ("Cannot open %s\n", file);
421 }
422 }
423 closedir (dh);
424 #endif
425 #endif
426 return true;
427 }
428
r_lib_add_handler(RLib * lib,int type,const char * desc,int (* cb)(RLibPlugin *,void *,void *),int (* dt)(RLibPlugin *,void *,void *),void * user)429 R_API bool r_lib_add_handler(RLib *lib,
430 int type, const char *desc,
431 int (*cb)(RLibPlugin *, void *, void *), /* constructor */
432 int (*dt)(RLibPlugin *, void *, void *), /* destructor */
433 void *user)
434 {
435 RLibHandler *h;
436 RListIter *iter;
437 RLibHandler *handler = NULL;
438
439 r_list_foreach (lib->handlers, iter, h) {
440 if (type == h->type) {
441 IFDBG eprintf ("Redefining library handler constructor for %d\n", type);
442 handler = h;
443 break;
444 }
445 }
446 if (!handler) {
447 handler = R_NEW (RLibHandler);
448 if (!handler) {
449 return false;
450 }
451 handler->type = type;
452 r_list_append (lib->handlers, handler);
453 }
454 strncpy (handler->desc, desc, sizeof (handler->desc)-1);
455 handler->user = user;
456 handler->constructor = cb;
457 handler->destructor = dt;
458
459 return true;
460 }
461
r_lib_del_handler(RLib * lib,int type)462 R_API bool r_lib_del_handler(RLib *lib, int type) {
463 RLibHandler *h;
464 RListIter *iter;
465 // TODO: remove all handlers for that type? or only one?
466 /* No _safe loop necessary because we return immediately after the delete. */
467 r_list_foreach (lib->handlers, iter, h) {
468 if (type == h->type) {
469 r_list_delete (lib->handlers, iter);
470 return true;
471 }
472 }
473 return false;
474 }
475
476 // TODO _list methods should not exist.. only used in ../core/cmd_log.c: r_lib_list (core->lib);
r_lib_list(RLib * lib)477 R_API void r_lib_list(RLib *lib) {
478 RListIter *iter;
479 RLibPlugin *p;
480 r_list_foreach (lib->plugins, iter, p) {
481 printf (" %5s %p %s \n", __lib_types_get (p->type),
482 p->dl_handler, p->file);
483 }
484 }
485