Rizin
unix-like reverse engineering framework and cli tools
serialize_functions.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 Anton Kochkov <anton.kochkov@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_util/rz_serialize.h>
5 #include <rz_list.h>
6 #include <rz_vector.h>
7 #include <rz_type.h>
8 #include <sdb.h>
9 
17 static RzType *parse_type_string_cached(RzTypeParser *parser, HtPP *cache, const char *str, char **error_msg, RZ_OUT RzList *newly_added) {
19  RzType *r = ht_pp_find(cache, str, NULL);
20  if (r) {
21  *error_msg = NULL;
22  return rz_type_clone(r);
23  }
24  r = rz_type_parse_string_single(parser, str, error_msg);
25  if (r) {
26  char *reminder = strdup(str);
27  if (reminder) {
28  ht_pp_insert(cache, str, r);
29  rz_list_push(newly_added, reminder);
30  }
31  }
32  return r;
33 }
34 
35 static void type_string_cache_rollback(HtPP *cache, RzList *newly_added) {
36  RzListIter *it;
37  char *s;
38  rz_list_foreach (newly_added, it, s) {
39  ht_pp_delete(cache, s);
40  }
41 }
42 
43 static RzCallable *get_callable_type(RzTypeDB *typedb, Sdb *sdb, const char *name, HtPP *type_str_cache) {
45 
46  RzList *cache_newly_added = rz_list_newf(free);
47  if (!cache_newly_added) {
48  return NULL;
49  }
50 
51  RzCallable *callable = rz_type_func_new(typedb, name, NULL);
52  if (!callable) {
53  rz_list_free(cache_newly_added);
54  return NULL;
55  }
56 
57  RzStrBuf key;
58  size_t arguments = sdb_num_get(sdb, rz_strbuf_initf(&key, "func.%s.args", name), 0);
59  if (arguments > 0 && !rz_pvector_reserve(callable->args, arguments)) {
60  goto error;
61  }
62 
63  int i;
64  for (i = 0; i < arguments; i++) {
65  char *values = sdb_get(sdb, rz_strbuf_setf(&key, "func.%s.arg.%d", name, i), NULL);
66 
67  if (!values) {
68  goto error;
69  }
70  char arg_name[32];
71  char *argument_name;
72  char *argument_type = sdb_anext(values, &argument_name);
73  if (!argument_name) {
74  // Autoname unnamed arguments
75  argument_name = rz_strf(arg_name, "arg%d", i);
76  }
77  char *error_msg = NULL;
78  RzType *ttype = parse_type_string_cached(typedb->parser, type_str_cache, argument_type, &error_msg, cache_newly_added);
79  if (!ttype || error_msg) {
80  eprintf("error parsing \"%s\" func arg type \"%s\": %s\n", name, argument_type, error_msg);
81  free(values);
82  goto error;
83  }
85  if (!arg) {
86  free(values);
87  rz_type_free(ttype);
88  goto error;
89  }
90  arg->name = strdup(argument_name);
91  arg->type = ttype;
92  free(values);
93 
94  void *element = rz_pvector_push(callable->args, arg); // returns null if no space available
95  if (!element) {
97  goto error;
98  }
99  }
100 
101  const char *rettype = sdb_const_get(sdb, rz_strbuf_setf(&key, "func.%s.ret", name), 0);
102  if (!rettype) {
103  // best we can do for a broken database
104  rettype = "void";
105  }
106 
107  char *error_msg = NULL;
108  RzType *ttype = parse_type_string_cached(typedb->parser, type_str_cache, rettype, &error_msg, cache_newly_added);
109  if (!ttype || error_msg) {
110  eprintf("error parsing \"%s\" func return type \"%s\": %s \n", name, rettype, error_msg);
111  free(error_msg);
112  goto error;
113  }
114  callable->ret = ttype;
115 
116  // Optional "noreturn" attribute
117  callable->noret = sdb_bool_get(sdb, rz_strbuf_setf(&key, "func.%s.noreturn", name), 0);
118 
120  rz_list_free(cache_newly_added);
121  return callable;
122 
123 error:
124  // remove any types from the cache that will be freed by the callable_free below
125  type_string_cache_rollback(type_str_cache, cache_newly_added);
126  rz_list_free(cache_newly_added);
127  rz_type_callable_free(callable);
129  return NULL;
130 }
131 
132 static bool filter_func(void *user, const char *k, const char *v) {
133  return !strcmp(v, "func");
134 }
135 
136 static bool sdb_load_callables(RzTypeDB *typedb, Sdb *sdb) {
137  rz_return_val_if_fail(typedb && sdb, false);
138  HtPP *type_str_cache = ht_pp_new0(); // cache from a known C type extr to its RzType representation for skipping the parser if possible
139  if (!type_str_cache) {
140  return false;
141  }
142  RzCallable *callable;
143  SdbKv *kv;
144  SdbListIter *iter;
145  SdbList *l = sdb_foreach_list_filter(sdb, filter_func, false);
146  ls_foreach (l, iter, kv) {
147  // eprintf("loading function: \"%s\"\n", sdbkv_key(kv));
148  callable = get_callable_type(typedb, sdb, sdbkv_key(kv), type_str_cache);
149  if (callable) {
150  ht_pp_update(typedb->callables, callable->name, callable);
151  RZ_LOG_DEBUG("inserting the \"%s\" callable type\n", callable->name);
152  }
153  }
154  ht_pp_free(type_str_cache);
155  ls_free(l);
156  return true;
157 }
158 
159 static bool sdb_load_by_path(RZ_NONNULL RzTypeDB *typedb, RZ_NONNULL const char *path) {
160  rz_return_val_if_fail(typedb && path, false);
161  if (RZ_STR_ISEMPTY(path)) {
162  return false;
163  }
164  Sdb *db = sdb_new(0, path, 0);
165  bool result = sdb_load_callables(typedb, db);
166  sdb_close(db);
167  sdb_free(db);
168  return result;
169 }
170 
171 static bool sdb_load_from_string(RZ_NONNULL RzTypeDB *typedb, RZ_NONNULL const char *string) {
172  rz_return_val_if_fail(typedb && string, false);
173  if (RZ_STR_ISEMPTY(string)) {
174  return false;
175  }
176  Sdb *db = sdb_new0();
177  sdb_query_lines(db, string);
178  bool result = sdb_load_callables(typedb, db);
179  sdb_close(db);
180  sdb_free(db);
181  return result;
182 }
183 
184 static void save_callable(const RzTypeDB *typedb, Sdb *sdb, const RzCallable *callable) {
185  rz_return_if_fail(typedb && sdb && callable && callable->name);
186  /*
187  C:
188  type name (type param1, type param2, type paramN);
189  Sdb:
190  name=func
191  func.name.args=N
192  func.name.arg.0=type,param1
193  func.name.arg.1=type,param2
194  func.name.arg.N=type,paramN
195  func.name.ret=type
196  */
197  const char *cname = callable->name;
198  // name=func
199  sdb_set(sdb, cname, "func", 0);
200 
201  // func.name.args=N
202  char *key = rz_str_newf("func.%s.args", cname);
203  sdb_num_set(sdb, key, rz_pvector_len(callable->args), 0);
204  free(key);
205 
206  RzStrBuf param_key;
207  RzStrBuf param_val;
208  rz_strbuf_init(&param_key);
209  rz_strbuf_init(&param_val);
210 
211  size_t i = 0;
212  void **it;
213  rz_pvector_foreach (callable->args, it) {
214  RzCallableArg *arg = *it;
215  // func.name.arg.N=type,paramN
216  char *arg_name = rz_str_sanitize_sdb_key(arg->name);
217  char *arg_type = rz_type_as_string(typedb, arg->type);
218  sdb_set(sdb,
219  rz_strbuf_setf(&param_key, "func.%s.arg.%zu", cname, i),
220  rz_strbuf_setf(&param_val, "%s,%s", arg_type, arg_name), 0ULL);
221  free(arg_name);
222  free(arg_type);
223  }
224  rz_strbuf_fini(&param_key);
225  rz_strbuf_fini(&param_val);
226 
227  // func.name.ret=type
228  if (callable->ret) {
229  key = rz_str_newf("func.%s.ret", cname);
230  char *ret_type = rz_type_as_string(typedb, callable->ret);
231  sdb_set(sdb, key, ret_type, 0);
232  free(key);
233  }
234 
235  // Optional "noreturn" attribute
236  if (callable->noret) {
237  char *noreturn_key = rz_str_newf("func.%s.noreturn", cname);
238  sdb_bool_set(sdb, noreturn_key, true, 0);
239  }
240 }
241 
242 struct typedb_sdb {
243  const RzTypeDB *typedb;
245 };
246 
247 static bool export_callable_cb(void *user, const void *k, const void *v) {
248  struct typedb_sdb *s = user;
249  RzCallable *callable = (RzCallable *)v;
250  save_callable(s->typedb, s->sdb, callable);
251  return true;
252 }
253 
255  struct typedb_sdb tdb = { typedb, db };
256  ht_pp_foreach(typedb->callables, export_callable_cb, &tdb);
257  return true;
258 }
259 
267  rz_return_val_if_fail(typedb && path, false);
268  if (!rz_file_exists(path)) {
269  return false;
270  }
271  return sdb_load_by_path(typedb, path);
272 }
273 
281  rz_return_val_if_fail(typedb && str, false);
282  if (RZ_STR_ISEMPTY(str)) {
283  return false;
284  }
286 }
287 
295  rz_return_if_fail(db && typedb);
297 }
298 
307  rz_return_val_if_fail(db && typedb, false);
308  return sdb_load_callables(typedb, db);
309 }
lzma_index ** i
Definition: index.h:629
RZ_API RZ_OWN RzType * rz_type_parse_string_single(RzTypeParser *parser, const char *code, char **error_msg)
Parses the single C type definition.
Definition: c_cpp_parser.c:309
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len key
Definition: sflib.h:118
const char * k
Definition: dsignal.c:11
const char * v
Definition: dsignal.c:12
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_BORROW RzListIter * rz_list_push(RZ_NONNULL RzList *list, void *item)
Alias for rz_list_append.
Definition: list.c:60
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RZ_API int sdb_query_lines(Sdb *s, const char *cmd)
Definition: query.c:800
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
RZ_API void ls_free(SdbList *list)
Definition: ls.c:191
#define ls_foreach(list, it, pos)
Definition: ls.h:31
RZ_API bool sdb_bool_get(Sdb *db, const char *str, ut32 *cas)
Definition: num.c:76
RZ_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas)
Definition: num.c:25
RZ_API int sdb_bool_set(Sdb *db, const char *str, bool v, ut32 cas)
Definition: num.c:72
RZ_API ut64 sdb_num_get(Sdb *s, const char *key, ut32 *cas)
Definition: num.c:13
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API bool rz_file_exists(const char *str)
Definition: file.c:192
#define RZ_LOG_DEBUG(fmtstr,...)
Definition: rz_log.h:49
#define RZ_STR_ISNOTEMPTY(x)
Definition: rz_str.h:68
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_sanitize_sdb_key(const char *s)
Definition: str.c:1405
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
#define rz_strf(buf,...)
Convenience macro for local temporary strings.
Definition: rz_str.h:59
RZ_API const char * rz_strbuf_initf(RzStrBuf *sb, const char *fmt,...)
Definition: strbuf.c:38
RZ_API const char * rz_strbuf_setf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API void rz_strbuf_fini(RzStrBuf *sb)
Definition: strbuf.c:365
RZ_API void rz_strbuf_init(RzStrBuf *sb)
Definition: strbuf.c:33
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_OUT
Definition: rz_types.h:51
#define RZ_NONNULL
Definition: rz_types.h:64
static void ** rz_pvector_reserve(RzPVector *vec, size_t capacity)
Definition: rz_vector.h:312
static size_t rz_pvector_len(const RzPVector *vec)
Definition: rz_vector.h:231
static void ** rz_pvector_push(RzPVector *vec, void *x)
Definition: rz_vector.h:300
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
RZ_API Sdb * sdb_new(const char *path, const char *name, int lock)
Definition: sdb.c:47
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611
RZ_API void sdb_close(Sdb *s)
Definition: sdb.c:416
RZ_API Sdb * sdb_new0(void)
Definition: sdb.c:43
RZ_API char * sdb_get(Sdb *s, const char *key, ut32 *cas)
Definition: sdb.c:290
RZ_API bool sdb_free(Sdb *s)
Definition: sdb.c:206
RZ_API const char * sdb_const_get(Sdb *s, const char *key, ut32 *cas)
Definition: sdb.c:279
RZ_API SdbList * sdb_foreach_list_filter(Sdb *s, SdbForeachCallback filter, bool sorted)
Definition: sdb.c:685
RZ_API char * sdb_anext(char *str, char **next)
Definition: util.c:192
static char * sdbkv_key(const SdbKv *kv)
Definition: sdbht.h:21
RZ_API bool rz_type_db_load_callables_sdb_str(RzTypeDB *typedb, RZ_NONNULL const char *str)
Loads the callable types from SDB KV string.
static RzType * parse_type_string_cached(RzTypeParser *parser, HtPP *cache, const char *str, char **error_msg, RZ_OUT RzList *newly_added)
static RzCallable * get_callable_type(RzTypeDB *typedb, Sdb *sdb, const char *name, HtPP *type_str_cache)
RZ_API bool rz_serialize_callables_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzTypeDB *typedb, RZ_NULLABLE RzSerializeResultInfo *res)
Loads the callable types from SDB.
static bool sdb_load_by_path(RZ_NONNULL RzTypeDB *typedb, RZ_NONNULL const char *path)
RZ_API bool rz_type_db_load_callables_sdb(RzTypeDB *typedb, RZ_NONNULL const char *path)
Loads the callable types from compiled SDB specified by path.
static bool sdb_load_callables(RzTypeDB *typedb, Sdb *sdb)
static bool export_callable_cb(void *user, const void *k, const void *v)
static bool callable_export_sdb(RZ_NONNULL Sdb *db, RZ_NONNULL const RzTypeDB *typedb)
static void type_string_cache_rollback(HtPP *cache, RzList *newly_added)
RZ_API void rz_serialize_callables_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzTypeDB *typedb)
Saves the callable types into SDB.
static void save_callable(const RzTypeDB *typedb, Sdb *sdb, const RzCallable *callable)
static bool filter_func(void *user, const char *k, const char *v)
static bool sdb_load_from_string(RZ_NONNULL RzTypeDB *typedb, RZ_NONNULL const char *string)
const char * name
Definition: sparc-opc.c:1838
Definition: cname.h:39
Definition: ls.h:17
Definition: ls.h:22
Definition: z80asm.h:102
RzPVector * args
optional for the time being
Definition: rz_type.h:149
RZ_NULLABLE char * name
Definition: rz_type.h:147
RZ_NULLABLE RzType * ret
Definition: rz_type.h:148
RzTypeParser * parser
Definition: rz_type.h:37
HtPP * callables
Definition: rz_type.h:35
Definition: sdbht.h:14
Definition: sdb.h:63
const RzTypeDB * typedb
RZ_API RZ_OWN RzCallable * rz_type_func_new(RzTypeDB *typedb, RZ_NONNULL const char *name, RZ_OWN RZ_NULLABLE RzType *type)
Creates a new RzCallable type.
Definition: function.c:131
RZ_API void rz_type_callable_free(RZ_NONNULL RzCallable *callable)
Frees the RzCallable.
Definition: function.c:55
RZ_API void rz_type_callable_arg_free(RzCallableArg *arg)
Frees the RzCallableArg.
Definition: function.c:101
RZ_API void rz_type_free(RZ_NULLABLE RzType *type)
Frees the RzType.
Definition: type.c:1273
RZ_API RZ_OWN RzType * rz_type_clone(RZ_BORROW RZ_NONNULL const RzType *type)
Creates an exact clone of the RzType.
Definition: type.c:1181
RZ_API RZ_OWN char * rz_type_as_string(const RzTypeDB *typedb, RZ_NONNULL const RzType *type)
Returns the type C representation.
Definition: type.c:817
void error(const char *msg)
Definition: untgz.c:593