rizin/librz/parse/code.c
2021-03-16 14:01:22 +01:00

134 lines
3.1 KiB
C

// SPDX-FileCopyrightText: 2013-2019 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rz_util.h"
#include "rz_types.h"
#include "rz_parse.h"
#include "tcc.h"
extern int tcc_sym_push(char *typename, int typesize, int meta);
/* parse C code and return it in key-value form */
static void __appendString(const char *msg, char **s) {
if (!s) {
printf("%s\n", msg);
} else if (*s) {
char *p = malloc(strlen(msg) + strlen(*s) + 1);
if (p) {
strcpy(p, *s);
free(*s);
*s = p;
strcpy(p + strlen(p), msg);
}
} else {
*s = strdup(msg);
}
}
static bool __typeLoad(void *p, const char *k, const char *v) {
if (!p) {
return false;
}
int btype = 0;
RzAnalysis *analysis = (RzAnalysis *)p;
//rz_cons_printf ("tk %s=%s\n", k, v);
// TODO: Add unions support
if (!strncmp(v, "struct", 6) && strncmp(k, "struct.", 7)) {
// structure
btype = VT_STRUCT;
const char *typename = k;
int typesize = 0;
// TODO: Add typesize here
char *query = sdb_fmt("struct.%s", k);
char *members = sdb_get(analysis->sdb_types, query, 0);
char *next, *ptr = members;
if (members) {
do {
char *name = sdb_anext(ptr, &next);
if (!name) {
break;
}
query = sdb_fmt("struct.%s.%s", k, name);
char *subtype = sdb_get(analysis->sdb_types, query, 0);
if (!subtype) {
break;
}
char *tmp = strchr(subtype, ',');
if (tmp) {
*tmp++ = 0;
tmp = strchr(tmp, ',');
if (tmp) {
*tmp++ = 0;
}
char *subname = tmp;
// TODO: Go recurse here
query = sdb_fmt("struct.%s.%s.meta", subtype, subname);
btype = sdb_num_get(analysis->sdb_types, query, 0);
tcc_sym_push(subtype, 0, btype);
}
free(subtype);
ptr = next;
} while (next);
free(members);
}
tcc_sym_push((char *)typename, typesize, btype);
}
return true;
}
static void __errorFunc(void *opaque, const char *msg) {
__appendString(msg, opaque);
char **p = (char **)opaque;
if (p && *p) {
int n = strlen(*p);
char *ptr = malloc(n + 2);
if (!ptr) {
return;
}
strcpy(ptr, *p);
ptr[n] = '\n';
ptr[n + 1] = 0;
free(*p);
*p = ptr;
}
}
RZ_API char *rz_parse_c_file(RzAnalysis *analysis, const char *path, const char *dir, char **error_msg) {
char *str = NULL;
TCCState *T = tcc_new(analysis->cpu, analysis->bits, analysis->os);
if (!T) {
return NULL;
}
tcc_set_callback(T, &__appendString, &str);
tcc_set_error_func(T, (void *)error_msg, __errorFunc);
sdb_foreach(analysis->sdb_types, __typeLoad, analysis);
if (tcc_add_file(T, path, dir) == -1) {
free(str);
str = NULL;
}
tcc_delete(T);
return str;
}
RZ_API char *rz_parse_c_string(RzAnalysis *analysis, const char *code, char **error_msg) {
char *str = NULL;
TCCState *T = tcc_new(analysis->cpu, analysis->bits, analysis->os);
if (!T) {
return NULL;
}
tcc_set_callback(T, &__appendString, &str);
tcc_set_error_func(T, (void *)error_msg, __errorFunc);
sdb_foreach(analysis->sdb_types, __typeLoad, NULL);
if (tcc_compile_string(T, code) != 0) {
free(str);
str = NULL;
}
tcc_delete(T);
return str;
}
// XXX do not use globals
RZ_API void rz_parse_c_reset(RzParse *p) {
anon_sym = SYM_FIRST_ANOM;
}