2018-01-24 15:12:33 +01:00
|
|
|
/* radare - Copyright 2008-2018 - LGPL -- pancake */
|
2009-02-05 22:08:46 +01:00
|
|
|
|
2010-03-04 01:46:25 +01:00
|
|
|
#include <r_types.h>
|
|
|
|
#include <r_util.h>
|
|
|
|
#include <r_syscall.h>
|
2009-02-05 22:08:46 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2011-02-03 00:20:39 +01:00
|
|
|
#include "fastcall.h"
|
2009-02-05 22:08:46 +01:00
|
|
|
|
2013-06-14 02:51:33 +02:00
|
|
|
R_LIB_VERSION (r_syscall);
|
|
|
|
|
2018-01-24 15:12:33 +01:00
|
|
|
// TODO: now we use sdb
|
2010-09-24 16:45:56 +02:00
|
|
|
extern RSyscallPort sysport_x86[];
|
2016-06-29 16:17:41 +02:00
|
|
|
extern RSyscallPort sysport_avr[];
|
2009-02-05 22:08:46 +01:00
|
|
|
|
2018-03-14 12:58:16 +01:00
|
|
|
R_API RSyscall* r_syscall_ref(RSyscall *sc) {
|
|
|
|
sc->refs++;
|
|
|
|
return sc;
|
|
|
|
}
|
|
|
|
|
2010-02-12 00:43:11 +01:00
|
|
|
R_API RSyscall* r_syscall_new() {
|
2015-06-22 03:10:56 +02:00
|
|
|
RSyscall *rs = R_NEW0 (RSyscall);
|
2011-02-03 00:20:39 +01:00
|
|
|
if (rs) {
|
|
|
|
rs->sysport = sysport_x86;
|
2013-04-22 01:09:27 +02:00
|
|
|
rs->regs = fastcall_x86_32;
|
2018-01-24 15:12:33 +01:00
|
|
|
rs->srdb = sdb_new0 (); // sysregs database
|
2017-06-27 23:42:41 +02:00
|
|
|
rs->db = sdb_new0 ();
|
2011-02-03 00:20:39 +01:00
|
|
|
}
|
|
|
|
return rs;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2014-03-07 01:26:11 +01:00
|
|
|
R_API void r_syscall_free(RSyscall *s) {
|
2017-08-27 17:30:06 -07:00
|
|
|
if (s) {
|
2018-03-14 12:58:16 +01:00
|
|
|
if (s->refs > 0) {
|
|
|
|
s->refs--;
|
|
|
|
return;
|
|
|
|
}
|
2018-03-14 12:41:39 +01:00
|
|
|
sdb_free (s->srdb);
|
2017-08-27 17:30:06 -07:00
|
|
|
sdb_free (s->db);
|
|
|
|
free (s->os);
|
|
|
|
free (s);
|
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2011-02-03 00:20:39 +01:00
|
|
|
/* return fastcall register argument 'idx' for a syscall with 'num' args */
|
|
|
|
R_API const char *r_syscall_reg(RSyscall *s, int idx, int num) {
|
2017-06-28 00:24:26 +02:00
|
|
|
if (num < 0 || num >= R_SYSCALL_ARGS || idx < 0 || idx >= R_SYSCALL_ARGS) {
|
2011-02-03 00:20:39 +01:00
|
|
|
return NULL;
|
2016-09-26 13:38:30 +02:00
|
|
|
}
|
2011-02-03 00:20:39 +01:00
|
|
|
return s->regs[num].arg[idx];
|
|
|
|
}
|
|
|
|
|
2018-01-24 15:12:33 +01:00
|
|
|
static Sdb *openDatabase(Sdb *db, const char *name) {
|
|
|
|
#define SYSCALLPATH "/share/radare2/" R2_VERSION
|
|
|
|
const char *file = sdb_fmt (0, "%s/%s/%s.sdb",
|
|
|
|
r_sys_prefix (NULL), SYSCALLPATH, name);
|
|
|
|
if (!r_file_exists (file)) {
|
2018-01-26 12:03:07 +01:00
|
|
|
// eprintf ("r_syscall_setup: Cannot find '%s'\n", file);
|
2018-01-24 15:12:33 +01:00
|
|
|
return false;
|
|
|
|
}
|
2018-01-26 12:54:05 +01:00
|
|
|
if (!db) {
|
|
|
|
return sdb_new (0, file, 0);
|
|
|
|
}
|
|
|
|
sdb_reset (db);
|
|
|
|
sdb_open (db, file);
|
|
|
|
return db;
|
2018-01-24 15:12:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: should be renamed to r_syscall_use();
|
|
|
|
R_API bool r_syscall_setup(RSyscall *s, const char *arch, int bits, const char *cpu, const char *os) {
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!os || !*os) {
|
2010-03-04 01:46:25 +01:00
|
|
|
os = R_SYS_OS;
|
2016-10-26 22:31:33 +02:00
|
|
|
}
|
|
|
|
if (!arch) {
|
|
|
|
arch = R_SYS_ARCH;
|
|
|
|
}
|
2015-06-22 03:10:56 +02:00
|
|
|
free (s->os);
|
|
|
|
s->os = strdup (os);
|
|
|
|
|
2016-06-29 16:17:41 +02:00
|
|
|
if (!strcmp (os, "any")) { // ignored
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2016-06-29 16:17:41 +02:00
|
|
|
}
|
|
|
|
if (!strcmp (arch, "mips")) {
|
2014-03-07 01:26:11 +01:00
|
|
|
s->regs = fastcall_mips;
|
2017-11-26 22:42:56 +01:00
|
|
|
} else if (!strcmp (arch, "avr")) {
|
2016-06-29 16:17:41 +02:00
|
|
|
s->sysport = sysport_avr;
|
2017-11-26 22:42:56 +01:00
|
|
|
} else if (!strcmp (os, "osx") || !strcmp (os, "macos")) {
|
2017-11-27 00:41:53 +05:30
|
|
|
os = "darwin";
|
2016-06-29 16:17:41 +02:00
|
|
|
} else if (!strcmp (arch,"sh")) {
|
2014-03-07 01:26:11 +01:00
|
|
|
s->regs = fastcall_sh;
|
2016-06-29 16:17:41 +02:00
|
|
|
} else if (!strcmp (arch, "arm")) {
|
2016-11-08 01:58:07 +01:00
|
|
|
switch (bits) {
|
|
|
|
case 16:
|
|
|
|
case 32:
|
|
|
|
s->regs = fastcall_arm;
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
s->regs = fastcall_arm64;
|
|
|
|
break;
|
|
|
|
}
|
2016-06-29 16:17:41 +02:00
|
|
|
} else if (!strcmp (arch, "x86")) {
|
|
|
|
s->sysport = sysport_x86;
|
2013-04-22 01:09:27 +02:00
|
|
|
switch (bits) {
|
2014-08-18 15:03:02 +02:00
|
|
|
case 8:
|
|
|
|
s->regs = fastcall_x86_8;
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
s->regs = fastcall_x86_32;
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
s->regs = fastcall_x86_64;
|
2015-10-30 03:07:22 +01:00
|
|
|
break;
|
2013-04-22 01:09:27 +02:00
|
|
|
}
|
2011-09-04 05:33:59 +02:00
|
|
|
}
|
|
|
|
|
2018-01-24 15:12:33 +01:00
|
|
|
char *dbName = r_str_newf ("syscall/%s-%s-%d", os, arch, bits);
|
|
|
|
s->db = openDatabase (s->db, dbName);
|
|
|
|
free (dbName);
|
2011-09-04 05:33:59 +02:00
|
|
|
|
2018-01-24 15:12:33 +01:00
|
|
|
dbName = r_str_newf ("sysregs/%s-%d-%s", arch, bits, cpu ? cpu: arch);
|
2018-03-14 14:49:05 +01:00
|
|
|
sdb_free (s->srdb);
|
2018-01-24 15:12:33 +01:00
|
|
|
s->srdb = openDatabase (s->srdb, dbName);
|
|
|
|
free (dbName);
|
2016-10-26 22:31:33 +02:00
|
|
|
if (s->fd) {
|
2014-03-07 01:26:11 +01:00
|
|
|
fclose (s->fd);
|
2018-03-14 14:49:05 +01:00
|
|
|
s->fd = NULL;
|
2016-10-26 22:31:33 +02:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2011-09-04 03:56:35 +02:00
|
|
|
R_API RSyscallItem *r_syscall_item_new_from_string(const char *name, const char *s) {
|
2011-07-02 10:14:46 +02:00
|
|
|
RSyscallItem *si;
|
|
|
|
char *o;
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!name || !s) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-03-15 00:44:41 +01:00
|
|
|
o = strdup (s);
|
|
|
|
int cols = r_str_split (o, ',');
|
|
|
|
if (cols < 3) {
|
|
|
|
free (o);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-02 10:14:46 +02:00
|
|
|
si = R_NEW0 (RSyscallItem);
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!si) {
|
2018-03-19 11:51:04 +01:00
|
|
|
free (o);
|
2016-10-26 22:31:33 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-09-04 03:56:35 +02:00
|
|
|
si->name = strdup (name);
|
2018-03-15 00:44:41 +01:00
|
|
|
si->swi = (int)r_num_get (NULL, r_str_word_get0 (o, 0));
|
|
|
|
si->num = (int)r_num_get (NULL, r_str_word_get0 (o, 1));
|
|
|
|
si->args = (int)r_num_get (NULL, r_str_word_get0 (o, 2));
|
2017-03-05 22:30:53 +01:00
|
|
|
//in a definition such as syscall=0x80,0,4,
|
|
|
|
//the string at index 3 is 0 causing oob read afterwards
|
|
|
|
si->sargs = calloc (si->args + 1, sizeof (char));
|
|
|
|
if (!si->sargs) {
|
|
|
|
free (si);
|
|
|
|
free (o);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
strncpy (si->sargs, r_str_word_get0 (o, 3), si->args);
|
2011-09-04 03:56:35 +02:00
|
|
|
free (o);
|
|
|
|
return si;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_syscall_item_free(RSyscallItem *si) {
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!si) {
|
|
|
|
return;
|
|
|
|
}
|
2011-09-04 03:56:35 +02:00
|
|
|
free (si->name);
|
|
|
|
free (si->sargs);
|
|
|
|
free (si);
|
|
|
|
}
|
|
|
|
|
2016-11-15 19:26:55 +01:00
|
|
|
static int getswi(RSyscall *s, int swi) {
|
|
|
|
if (s && swi == -1) {
|
|
|
|
return r_syscall_get_swi (s);
|
2011-07-02 10:14:46 +02:00
|
|
|
}
|
|
|
|
return swi;
|
|
|
|
}
|
|
|
|
|
2016-11-15 19:26:55 +01:00
|
|
|
R_API int r_syscall_get_swi(RSyscall *s) {
|
|
|
|
return (int)sdb_array_get_num (s->db, "_", 0, NULL);
|
|
|
|
}
|
|
|
|
|
2014-03-07 01:26:11 +01:00
|
|
|
R_API RSyscallItem *r_syscall_get(RSyscall *s, int num, int swi) {
|
2014-10-13 05:02:24 +02:00
|
|
|
const char *ret, *ret2, *key;
|
2016-09-26 13:38:30 +02:00
|
|
|
if (!s || !s->db) {
|
|
|
|
eprintf ("Syscall database not loaded\n");
|
2011-09-04 05:33:59 +02:00
|
|
|
return NULL;
|
2016-09-26 13:38:30 +02:00
|
|
|
}
|
2016-11-15 19:26:55 +01:00
|
|
|
swi = getswi (s, swi);
|
2016-10-26 22:31:33 +02:00
|
|
|
if (swi < 16) {
|
|
|
|
key = sdb_fmt (0, "%d.%d", swi, num);
|
|
|
|
} else {
|
|
|
|
key = sdb_fmt (0, "0x%02x.%d", swi, num);
|
|
|
|
}
|
2014-10-13 05:02:24 +02:00
|
|
|
ret = sdb_const_get (s->db, key, 0);
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!ret) {
|
2017-11-27 00:41:53 +05:30
|
|
|
key = sdb_fmt (0, "0x%02x.0x%02x", swi, num); // Workaround until Syscall SDB is fixed
|
|
|
|
ret = sdb_const_get (s->db, key, 0);
|
|
|
|
if (!ret) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-10-26 22:31:33 +02:00
|
|
|
}
|
2014-10-13 05:02:24 +02:00
|
|
|
ret2 = sdb_const_get (s->db, ret, 0);
|
2016-09-19 13:44:47 +01:00
|
|
|
if (!ret2) {
|
2011-07-02 10:14:46 +02:00
|
|
|
return NULL;
|
2014-10-13 05:02:24 +02:00
|
|
|
}
|
2016-11-16 03:02:50 +01:00
|
|
|
return r_syscall_item_new_from_string (ret, ret2);
|
2010-03-04 01:46:25 +01:00
|
|
|
}
|
|
|
|
|
2014-03-07 01:26:11 +01:00
|
|
|
R_API int r_syscall_get_num(RSyscall *s, const char *str) {
|
2016-09-26 13:38:30 +02:00
|
|
|
if (!s || !s->db) {
|
2014-06-14 02:01:03 +02:00
|
|
|
return -1;
|
2016-09-26 13:38:30 +02:00
|
|
|
}
|
2014-10-13 05:02:24 +02:00
|
|
|
return (int)sdb_array_get_num (s->db, str, 1, NULL);
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2014-06-14 02:01:03 +02:00
|
|
|
R_API const char *r_syscall_get_i(RSyscall *s, int num, int swi) {
|
2014-03-07 01:26:11 +01:00
|
|
|
char foo[32];
|
2016-09-26 13:38:30 +02:00
|
|
|
if (!s || !s->db) {
|
2011-09-04 05:33:59 +02:00
|
|
|
return NULL;
|
2016-09-26 13:38:30 +02:00
|
|
|
}
|
2016-11-15 19:26:55 +01:00
|
|
|
swi = getswi (s, swi);
|
2011-09-04 05:33:59 +02:00
|
|
|
snprintf (foo, sizeof (foo), "0x%x.%d", swi, num);
|
2014-06-14 02:01:03 +02:00
|
|
|
return sdb_const_get (s->db, foo, 0);
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2014-03-07 01:26:11 +01:00
|
|
|
static int callback_list(void *u, const char *k, const char *v) {
|
2014-10-19 22:43:33 +02:00
|
|
|
RList *list = (RList*)u;
|
2014-10-13 05:02:24 +02:00
|
|
|
if (!strchr (k, '.')) {
|
2014-10-19 22:43:33 +02:00
|
|
|
RSyscallItem *si = r_syscall_item_new_from_string (k, v);
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!si) {
|
2018-03-15 00:44:41 +01:00
|
|
|
return 1;
|
2016-10-26 22:31:33 +02:00
|
|
|
}
|
|
|
|
if (!strchr (si->name, '.')) {
|
2014-10-19 22:43:33 +02:00
|
|
|
r_list_append (list, si);
|
2016-10-26 22:31:33 +02:00
|
|
|
}
|
2014-10-13 05:02:24 +02:00
|
|
|
}
|
2014-03-07 01:26:11 +01:00
|
|
|
return 1; // continue loop
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API RList *r_syscall_list(RSyscall *s) {
|
2014-10-13 05:02:24 +02:00
|
|
|
RList *list;
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!s || !s->db) {
|
2014-06-14 02:01:03 +02:00
|
|
|
return NULL;
|
2016-10-26 22:31:33 +02:00
|
|
|
}
|
2014-10-13 05:02:24 +02:00
|
|
|
// show list of syscalls to stdout
|
2014-10-19 22:43:33 +02:00
|
|
|
list = r_list_newf ((RListFree)r_syscall_item_free);
|
|
|
|
sdb_foreach (s->db, callback_list, list);
|
2014-10-13 05:02:24 +02:00
|
|
|
return list;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
2016-06-29 16:17:41 +02:00
|
|
|
|
2018-01-24 15:12:33 +01:00
|
|
|
/* io and sysregs */
|
2016-06-29 16:17:41 +02:00
|
|
|
R_API const char *r_syscall_get_io(RSyscall *s, int ioport) {
|
|
|
|
int i;
|
2016-10-26 22:31:33 +02:00
|
|
|
if (!s) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-24 15:12:33 +01:00
|
|
|
const char *name = r_syscall_sysreg (s, "io", ioport);
|
|
|
|
if (name) {
|
|
|
|
return name;
|
|
|
|
}
|
2016-10-26 22:31:33 +02:00
|
|
|
for (i = 0; s->sysport[i].name; i++) {
|
|
|
|
if (ioport == s->sysport[i].port) {
|
2016-06-29 16:17:41 +02:00
|
|
|
return s->sysport[i].name;
|
2016-10-26 22:31:33 +02:00
|
|
|
}
|
2016-06-29 16:17:41 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-24 15:12:33 +01:00
|
|
|
R_API const char* r_syscall_sysreg(RSyscall *s, const char *type, ut64 num) {
|
|
|
|
if (!s || !s->db) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
const char *key = sdb_fmt (0, "%s,%"PFMT64d, type, num);
|
|
|
|
return sdb_const_get (s->db, key, 0);
|
|
|
|
}
|