1 /* radare - LGPL - Copyright 2008-2020 - nibble, pancake, thestr4ng3r */
2
3 #include <r_anal.h>
4 #include <r_core.h>
5
item_matches_filter(RAnalMetaItem * item,RAnalMetaType type,R_NULLABLE const RSpace * space)6 static bool item_matches_filter(RAnalMetaItem *item, RAnalMetaType type, R_NULLABLE const RSpace *space) {
7 return (type == R_META_TYPE_ANY || item->type == type)
8 && (!space || item->space == space);
9 }
10
11 typedef struct {
12 RAnalMetaType type;
13 const RSpace *space;
14
15 RIntervalNode *node;
16 } FindCtx;
17
find_node_cb(RIntervalNode * node,void * user)18 static bool find_node_cb(RIntervalNode *node, void *user) {
19 FindCtx *ctx = user;
20 if (item_matches_filter (node->data, ctx->type, ctx->space)) {
21 ctx->node = node;
22 return false;
23 }
24 return true;
25 }
26
find_node_at(RAnal * anal,RAnalMetaType type,R_NULLABLE const RSpace * space,ut64 addr)27 static RIntervalNode *find_node_at(RAnal *anal, RAnalMetaType type, R_NULLABLE const RSpace *space, ut64 addr) {
28 FindCtx ctx = {
29 .type = type,
30 .space = space,
31 .node = NULL
32 };
33 r_interval_tree_all_at (&anal->meta, addr, find_node_cb, &ctx);
34 return ctx.node;
35 }
36
find_node_in(RAnal * anal,RAnalMetaType type,R_NULLABLE const RSpace * space,ut64 addr)37 static RIntervalNode *find_node_in(RAnal *anal, RAnalMetaType type, R_NULLABLE const RSpace *space, ut64 addr) {
38 FindCtx ctx = {
39 .type = type,
40 .space = space,
41 .node = NULL
42 };
43 r_interval_tree_all_in (&anal->meta, addr, true, find_node_cb, &ctx);
44 return ctx.node;
45 }
46
47 typedef struct {
48 RAnalMetaType type;
49 const RSpace *space;
50
51 RPVector/*RIntervalNode*/ *result;
52 } CollectCtx;
53
collect_nodes_cb(RIntervalNode * node,void * user)54 static bool collect_nodes_cb(RIntervalNode *node, void *user) {
55 CollectCtx *ctx = user;
56 if (item_matches_filter (node->data, ctx->type, ctx->space)) {
57 r_pvector_push (ctx->result, node);
58 }
59 return true;
60 }
61
collect_nodes_at(RAnal * anal,RAnalMetaType type,R_NULLABLE const RSpace * space,ut64 addr)62 static RPVector *collect_nodes_at(RAnal *anal, RAnalMetaType type, R_NULLABLE const RSpace *space, ut64 addr) {
63 CollectCtx ctx = {
64 .type = type,
65 .space = space,
66 .result = r_pvector_new (NULL)
67 };
68 if (!ctx.result) {
69 return NULL;
70 }
71 r_interval_tree_all_at (&anal->meta, addr, collect_nodes_cb, &ctx);
72 return ctx.result;
73 }
74
collect_nodes_in(RAnal * anal,RAnalMetaType type,R_NULLABLE const RSpace * space,ut64 addr)75 static RPVector *collect_nodes_in(RAnal *anal, RAnalMetaType type, R_NULLABLE const RSpace *space, ut64 addr) {
76 CollectCtx ctx = {
77 .type = type,
78 .space = space,
79 .result = r_pvector_new (NULL)
80 };
81 if (!ctx.result) {
82 return NULL;
83 }
84 r_interval_tree_all_in (&anal->meta, addr, true, collect_nodes_cb, &ctx);
85 return ctx.result;
86 }
87
collect_nodes_intersect(RAnal * anal,RAnalMetaType type,R_NULLABLE const RSpace * space,ut64 start,ut64 end)88 static RPVector *collect_nodes_intersect(RAnal *anal, RAnalMetaType type, R_NULLABLE const RSpace *space, ut64 start, ut64 end) {
89 CollectCtx ctx = {
90 .type = type,
91 .space = space,
92 .result = r_pvector_new (NULL)
93 };
94 if (!ctx.result) {
95 return NULL;
96 }
97 r_interval_tree_all_intersect (&anal->meta, start, end, true, collect_nodes_cb, &ctx);
98 return ctx.result;
99 }
100
meta_set(RAnal * a,RAnalMetaType type,int subtype,ut64 from,ut64 to,const char * str)101 static bool meta_set(RAnal *a, RAnalMetaType type, int subtype, ut64 from, ut64 to, const char *str) {
102 if (to < from) {
103 return false;
104 }
105 RSpace *space = r_spaces_current (&a->meta_spaces);
106 RIntervalNode *node = find_node_at (a, type, space, from);
107 RAnalMetaItem *item = node ? node->data : R_NEW0 (RAnalMetaItem);
108 if (!item) {
109 return false;
110 }
111 item->type = type;
112 item->subtype = subtype;
113 item->space = space;
114 free (item->str);
115 item->str = str ? strdup (str) : NULL;
116 if (str && !item->str) {
117 if (!node) { // If we just created this
118 free (item);
119 }
120 return false;
121 }
122 if (!node) {
123 r_interval_tree_insert (&a->meta, from, to, item);
124 } else if (node->end != to) {
125 r_interval_tree_resize (&a->meta, node, from, to);
126 }
127 return true;
128 }
129
r_meta_set_string(RAnal * a,RAnalMetaType type,ut64 addr,const char * s)130 R_API bool r_meta_set_string(RAnal *a, RAnalMetaType type, ut64 addr, const char *s) {
131 return meta_set (a, type, 0, addr, addr, s);
132 }
133
r_meta_get_string(RAnal * a,RAnalMetaType type,ut64 addr)134 R_API const char *r_meta_get_string(RAnal *a, RAnalMetaType type, ut64 addr) {
135 RIntervalNode *node = find_node_at (a, type, r_spaces_current (&a->meta_spaces), addr);
136 if (!node) {
137 return NULL;
138 }
139 RAnalMetaItem *item = node->data;
140 return item->str;
141 }
142
143
del(RAnal * a,RAnalMetaType type,const RSpace * space,ut64 addr,ut64 size)144 static void del(RAnal *a, RAnalMetaType type, const RSpace *space, ut64 addr, ut64 size) {
145 RPVector *victims = NULL;
146 if (size == UT64_MAX) {
147 // delete everything
148 victims = r_pvector_new (NULL);
149 if (!victims) {
150 return;
151 }
152 RIntervalTreeIter it;
153 RAnalMetaItem *item;
154 r_interval_tree_foreach (&a->meta, it, item) {
155 if (item_matches_filter (item, type, space)) {
156 r_pvector_push (victims, r_interval_tree_iter_get (&it));
157 }
158 }
159 } else {
160 ut64 end = size ? addr + size - 1 : addr;
161 if (end < addr) {
162 end = UT64_MAX;
163 }
164 victims = collect_nodes_intersect (a, type, space, addr, end);
165 if (!victims) {
166 return;
167 }
168 }
169 void **it;
170 r_pvector_foreach (victims, it) {
171 r_interval_tree_delete (&a->meta, *it, true);
172 }
173 r_pvector_free (victims);
174 }
175
r_meta_del(RAnal * a,RAnalMetaType type,ut64 addr,ut64 size)176 R_API void r_meta_del(RAnal *a, RAnalMetaType type, ut64 addr, ut64 size) {
177 del (a, type, r_spaces_current (&a->meta_spaces), addr, size);
178 }
179
r_meta_set(RAnal * a,RAnalMetaType type,ut64 addr,ut64 size,const char * str)180 R_API bool r_meta_set(RAnal *a, RAnalMetaType type, ut64 addr, ut64 size, const char *str) {
181 return r_meta_set_with_subtype (a, type, 0, addr, size, str);
182 }
183
r_meta_set_with_subtype(RAnal * m,RAnalMetaType type,int subtype,ut64 addr,ut64 size,const char * str)184 R_API bool r_meta_set_with_subtype(RAnal *m, RAnalMetaType type, int subtype, ut64 addr, ut64 size, const char *str) {
185 r_return_val_if_fail (m && size, false);
186 ut64 end = addr + size - 1;
187 if (end < addr) {
188 end = UT64_MAX;
189 }
190 return meta_set (m, type, subtype, addr, end, str);
191 }
192
r_meta_get_at(RAnal * a,ut64 addr,RAnalMetaType type,R_OUT R_NULLABLE ut64 * size)193 R_API RAnalMetaItem *r_meta_get_at(RAnal *a, ut64 addr, RAnalMetaType type, R_OUT R_NULLABLE ut64 *size) {
194 RIntervalNode *node = find_node_at (a, type, r_spaces_current (&a->meta_spaces), addr);
195 if (node && size) {
196 *size = r_meta_item_size (node->start, node->end);
197 }
198 return node ? node->data : NULL;
199 }
200
r_meta_get_in(RAnal * a,ut64 addr,RAnalMetaType type)201 R_API RIntervalNode *r_meta_get_in(RAnal *a, ut64 addr, RAnalMetaType type) {
202 return find_node_in (a, type, r_spaces_current (&a->meta_spaces), addr);
203 }
204
r_meta_get_all_at(RAnal * a,ut64 at)205 R_API RPVector/*<RIntervalNode<RMetaItem> *>*/ *r_meta_get_all_at(RAnal *a, ut64 at) {
206 return collect_nodes_at (a, R_META_TYPE_ANY, r_spaces_current (&a->meta_spaces), at);
207 }
208
r_meta_get_all_in(RAnal * a,ut64 at,RAnalMetaType type)209 R_API RPVector *r_meta_get_all_in(RAnal *a, ut64 at, RAnalMetaType type) {
210 return collect_nodes_in (a, type, r_spaces_current (&a->meta_spaces), at);
211 }
212
r_meta_get_all_intersect(RAnal * a,ut64 start,ut64 size,RAnalMetaType type)213 R_API RPVector *r_meta_get_all_intersect(RAnal *a, ut64 start, ut64 size, RAnalMetaType type) {
214 r_return_val_if_fail (size, NULL);
215 ut64 end = start + size - 1;
216 if (end < start) {
217 end = UT64_MAX;
218 }
219 return collect_nodes_intersect (a, type, r_spaces_current (&a->meta_spaces), start, end);
220 }
221
r_meta_type_to_string(int type)222 R_API const char *r_meta_type_to_string(int type) {
223 // XXX: use type as '%c'
224 switch (type) {
225 case R_META_TYPE_DATA: return "Cd";
226 case R_META_TYPE_CODE: return "Cc";
227 case R_META_TYPE_STRING: return "Cs";
228 case R_META_TYPE_FORMAT: return "Cf";
229 case R_META_TYPE_MAGIC: return "Cm";
230 case R_META_TYPE_HIDE: return "Ch";
231 case R_META_TYPE_COMMENT: return "CCu";
232 case R_META_TYPE_RUN: return "Cr"; // not in C? help
233 case R_META_TYPE_HIGHLIGHT: return "ecHi"; // not in C?
234 case R_META_TYPE_VARTYPE: return "Ct";
235 }
236 return "# unknown meta # ";
237 }
238
r_meta_print(RAnal * a,RAnalMetaItem * d,ut64 start,ut64 size,int rad,PJ * pj,bool show_full)239 R_API void r_meta_print(RAnal *a, RAnalMetaItem *d, ut64 start, ut64 size, int rad, PJ *pj, bool show_full) {
240 r_return_if_fail (!(rad == 'j' && !pj)); // rad == 'j' => pj != NULL
241 char *pstr, *base64_str;
242 RCore *core = a->coreb.core;
243 bool esc_bslash = core ? core->print->esc_bslash : false;
244 if (r_spaces_current (&a->meta_spaces) &&
245 r_spaces_current (&a->meta_spaces) != d->space) {
246 return;
247 }
248 char *str = NULL;
249 if (d->str) {
250 if (d->type == R_META_TYPE_STRING) {
251 if (d->subtype == R_STRING_ENC_UTF8) {
252 str = r_str_escape_utf8 (d->str, false, esc_bslash);
253 } else {
254 if (!d->subtype) { /* temporary legacy workaround */
255 esc_bslash = false;
256 }
257 str = r_str_escape_latin1 (d->str, false, esc_bslash, false);
258 }
259 } else {
260 str = r_str_escape (d->str);
261 }
262 }
263 if (str || d->type == R_META_TYPE_DATA) {
264 if (d->type == R_META_TYPE_STRING && !*str) {
265 free (str);
266 return;
267 }
268 if (!str) {
269 pstr = "";
270 } else if (d->type == 'f') {
271 pstr = str;
272 } else if (d->type == 's') {
273 pstr = str;
274 } else if (d->type == 't') {
275 // Sanitize (don't escape) Ct comments so we can see "char *", etc.
276 free (str);
277 str = strdup (d->str);
278 r_str_sanitize (str);
279 pstr = str;
280 } else if (d->type != 'C') {
281 r_name_filter (str, 0);
282 pstr = str;
283 } else {
284 pstr = d->str;
285 }
286 // r_str_sanitize (str);
287 switch (rad) {
288 case 'j':
289 pj_o (pj);
290 pj_kn (pj, "offset", start);
291 pj_ks (pj, "type", r_meta_type_to_string (d->type));
292
293 if (d->type == 'H') {
294 pj_k (pj, "color");
295 ut8 r = 0, g = 0, b = 0, A = 0;
296 const char *esc = strchr (d->str, '\x1b');
297 if (esc) {
298 r_cons_rgb_parse (esc, &r, &g, &b, &A);
299 char *rgb_str = r_cons_rgb_tostring (r, g, b);
300 base64_str = r_base64_encode_dyn (rgb_str, -1);
301 if (d->type == 's' && base64_str) {
302 pj_s (pj, base64_str);
303 free (base64_str);
304 } else {
305 pj_s (pj, rgb_str);
306 }
307 free (rgb_str);
308 } else {
309 pj_s (pj, str);
310 }
311 } else {
312 pj_k (pj, "name");
313 if (d->type == 's' && (base64_str = r_base64_encode_dyn (d->str, -1))) {
314 pj_s (pj, base64_str);
315 } else {
316 pj_s (pj, str);
317 }
318 }
319 if (d->type == 'd') {
320 pj_kn (pj, "size", size);
321 } else if (d->type == 's') {
322 const char *enc;
323 switch (d->subtype) {
324 case R_STRING_ENC_UTF8:
325 enc = "utf8";
326 break;
327 case 0: /* temporary legacy encoding */
328 enc = "iz";
329 break;
330 default:
331 enc = "latin1";
332 }
333 pj_ks (pj, "enc", enc);
334 pj_kb (pj, "ascii", r_str_is_ascii (d->str));
335 }
336
337 pj_end (pj);
338 break;
339 case 0:
340 case 1:
341 case '*':
342 default:
343 switch (d->type) {
344 case R_META_TYPE_COMMENT:
345 {
346 const char *type = r_meta_type_to_string (d->type);
347 char *s = sdb_encode ((const ut8*)pstr, -1);
348 if (!s) {
349 s = strdup (pstr);
350 }
351 if (rad) {
352 if (!strcmp (type, "CCu")) {
353 a->cb_printf ("%s base64:%s @ 0x%08"PFMT64x"\n",
354 type, s, start);
355 } else {
356 a->cb_printf ("%s %s @ 0x%08"PFMT64x"\n",
357 type, pstr, start);
358 }
359 } else {
360 if (!strcmp (type, "CCu")) {
361 char *mys = r_str_escape (pstr);
362 a->cb_printf ("0x%08"PFMT64x" %s \"%s\"\n",
363 start, type, mys);
364 free (mys);
365 } else {
366 a->cb_printf ("0x%08"PFMT64x" %s \"%s\"\n",
367 start, type, pstr);
368 }
369 }
370 free (s);
371 }
372 break;
373 case R_META_TYPE_STRING:
374 if (rad) {
375 char cmd[] = "Cs#";
376 switch (d->subtype) {
377 case 'a':
378 case '8':
379 cmd[2] = d->subtype;
380 break;
381 default:
382 cmd[2] = 0;
383 }
384 a->cb_printf ("%s %"PFMT64u" @ 0x%08"PFMT64x" # %s\n",
385 cmd, size, start, pstr);
386 } else {
387 const char *enc;
388 switch (d->subtype) {
389 case '8':
390 enc = "utf8";
391 break;
392 default:
393 enc = r_str_is_ascii (d->str) ? "ascii" : "latin1";
394 }
395 if (show_full) {
396 a->cb_printf ("0x%08"PFMT64x" %s[%"PFMT64u"] \"%s\"\n",
397 start, enc, size, pstr);
398 } else {
399 a->cb_printf ("%s[%"PFMT64u"] \"%s\"\n",
400 enc, size, pstr);
401 }
402 }
403 break;
404 case R_META_TYPE_HIDE:
405 case R_META_TYPE_DATA:
406 if (rad) {
407 a->cb_printf ("%s %"PFMT64u" @ 0x%08"PFMT64x"\n",
408 r_meta_type_to_string (d->type),
409 size, start);
410 } else {
411 if (show_full) {
412 const char *dtype = d->type == 'h' ? "hidden" : "data";
413 a->cb_printf ("0x%08" PFMT64x " %s %s %"PFMT64u"\n",
414 start, dtype,
415 r_meta_type_to_string (d->type), size);
416 } else {
417 a->cb_printf ("%"PFMT64u"\n", size);
418 }
419 }
420 break;
421 case R_META_TYPE_MAGIC:
422 case R_META_TYPE_FORMAT:
423 if (rad) {
424 a->cb_printf ("%s %"PFMT64u" %s @ 0x%08"PFMT64x"\n",
425 r_meta_type_to_string (d->type),
426 size, pstr, start);
427 } else {
428 if (show_full) {
429 const char *dtype = d->type == 'm' ? "magic" : "format";
430 a->cb_printf ("0x%08" PFMT64x " %s %"PFMT64u" %s\n",
431 start, dtype, size, pstr);
432 } else {
433 a->cb_printf ("%"PFMT64u" %s\n", size, pstr);
434 }
435 }
436 break;
437 case R_META_TYPE_VARTYPE:
438 if (rad) {
439 a->cb_printf ("%s %s @ 0x%08"PFMT64x"\n",
440 r_meta_type_to_string (d->type), pstr, start);
441 } else {
442 a->cb_printf ("0x%08"PFMT64x" %s\n", start, pstr);
443 }
444 break;
445 case R_META_TYPE_HIGHLIGHT:
446 {
447 ut8 r = 0, g = 0, b = 0, A = 0;
448 const char *esc = strchr (d->str, '\x1b');
449 r_cons_rgb_parse (esc, &r, &g, &b, &A);
450 a->cb_printf ("%s rgb:%02x%02x%02x @ 0x%08"PFMT64x"\n",
451 r_meta_type_to_string (d->type), r, g, b, start);
452 // TODO: d->size
453 }
454 break;
455 default:
456 if (rad) {
457 a->cb_printf ("%s %"PFMT64u" 0x%08"PFMT64x" # %s\n",
458 r_meta_type_to_string (d->type),
459 size, start, pstr);
460 } else {
461 // TODO: use b64 here
462 a->cb_printf ("0x%08"PFMT64x" array[%"PFMT64u"] %s %s\n",
463 start, size,
464 r_meta_type_to_string (d->type), pstr);
465 }
466 break;
467 }
468 break;
469 }
470 if (str) {
471 free (str);
472 }
473 }
474 }
475
r_meta_print_list_at(RAnal * a,ut64 addr,int rad,const char * tq)476 R_API void r_meta_print_list_at(RAnal *a, ut64 addr, int rad, const char *tq) {
477 RPVector *nodes = collect_nodes_at (a, R_META_TYPE_ANY, r_spaces_current (&a->meta_spaces), addr);
478 if (!nodes) {
479 return;
480 }
481 void **it;
482 r_pvector_foreach (nodes, it) {
483 RIntervalNode *node = *it;
484 r_meta_print (a, node->data, node->start, r_meta_node_size (node), rad, NULL, true);
485 }
486 r_pvector_free (nodes);
487 }
488
print_meta_list(RAnal * a,int type,int rad,ut64 addr,const char * tq)489 static void print_meta_list(RAnal *a, int type, int rad, ut64 addr, const char *tq) {
490 PJ *pj = NULL;
491 RTable *t = NULL;
492 if (rad == ',') {
493 t = r_table_new ("meta");
494 RTableColumnType *s = r_table_type ("string");
495 RTableColumnType *n = r_table_type ("number");
496 r_table_add_column (t, n, "addr", 0);
497 r_table_add_column (t, n, "size", 0);
498 r_table_add_column (t, s, "type", 0);
499 r_table_add_column (t, s, "string", 0);
500 } else if (rad == 'j') {
501 pj = pj_new ();
502 if (!pj) {
503 return;
504 }
505 pj_a (pj);
506 }
507
508 RAnalFunction *fcn = NULL;
509 if (addr != UT64_MAX) {
510 fcn = r_anal_get_fcn_in (a, addr, 0);
511 if (!fcn) {
512 goto beach;
513 }
514 }
515
516 RIntervalTreeIter it;
517 RAnalMetaItem *item;
518 r_interval_tree_foreach (&a->meta, it, item) {
519 RIntervalNode *node = r_interval_tree_iter_get (&it);
520 if (type != R_META_TYPE_ANY && item->type != type) {
521 continue;
522 }
523 if (fcn && !r_anal_function_contains (fcn, node->start)) {
524 continue;
525 }
526 if (t) {
527 const char *type = r_meta_type_to_string (item->type);
528 const char *name = item->str;
529 r_table_add_rowf (t, "xxss",
530 node->start,
531 r_meta_node_size (node),
532 type, name);
533 } else {
534 r_meta_print (a, item, node->start, r_meta_node_size (node), rad, pj, true);
535 }
536 }
537
538 beach:
539 if (t) {
540 if (tq) {
541 r_table_query (t, tq);
542 }
543 char *s = r_table_tostring (t);
544 r_cons_printf ("%s\n", s);
545 free (s);
546 } else if (pj) {
547 pj_end (pj);
548 r_cons_printf ("%s\n", pj_string (pj));
549 pj_free (pj);
550 }
551 }
552
r_meta_print_list_all(RAnal * a,int type,int rad,const char * tq)553 R_API void r_meta_print_list_all(RAnal *a, int type, int rad, const char *tq) {
554 print_meta_list (a, type, rad, UT64_MAX, tq);
555 }
556
r_meta_print_list_in_function(RAnal * a,int type,int rad,ut64 addr,const char * tq)557 R_API void r_meta_print_list_in_function(RAnal *a, int type, int rad, ut64 addr, const char *tq) {
558 print_meta_list (a, type, rad, addr, tq);
559 }
560
r_meta_rebase(RAnal * anal,ut64 diff)561 R_API void r_meta_rebase(RAnal *anal, ut64 diff) {
562 if (!diff) {
563 return;
564 }
565 RIntervalTree old = anal->meta;
566 r_interval_tree_init (&anal->meta, old.free);
567 RIntervalTreeIter it;
568 RAnalMetaItem *item;
569 r_interval_tree_foreach (&old, it, item) {
570 RIntervalNode *node = r_interval_tree_iter_get (&it);
571 ut64 newstart = node->start + diff;
572 ut64 newend = node->end + diff;
573 if (newend < newstart) {
574 // Can't rebase this
575 newstart = node->start;
576 newend = node->end;
577 }
578 r_interval_tree_insert (&anal->meta, newstart, newend, item);
579 }
580 old.free = NULL;
581 r_interval_tree_fini (&old);
582 }
583
r_meta_space_unset_for(RAnal * a,const RSpace * space)584 R_API void r_meta_space_unset_for(RAnal *a, const RSpace *space) {
585 del (a, R_META_TYPE_ANY, space, 0, UT64_MAX);
586 }
587
r_meta_get_size(RAnal * a,RAnalMetaType type)588 R_API ut64 r_meta_get_size(RAnal *a, RAnalMetaType type) {
589 ut64 sum = 0;
590 RIntervalTreeIter it;
591 RAnalMetaItem *item;
592 RIntervalNode *prev = NULL;
593 r_interval_tree_foreach (&a->meta, it, item) {
594 RIntervalNode *node = r_interval_tree_iter_get (&it);
595 if (type != R_META_TYPE_ANY && item->type != type) {
596 continue;
597 }
598 ut64 start = R_MAX (prev ? prev->end : 0, node->start);
599 sum += node->end - start + 1;
600 prev = node;
601 }
602 return sum;
603 }
604
r_meta_space_count_for(RAnal * a,const RSpace * space)605 R_API int r_meta_space_count_for(RAnal *a, const RSpace *space) {
606 int r = 0;
607 RIntervalTreeIter it;
608 RAnalMetaItem *item;
609 r_interval_tree_foreach (&a->meta, it, item) {
610 if (item->space == space) {
611 r++;
612 }
613 }
614 return r;
615 }
616
r_meta_set_data_at(RAnal * a,ut64 addr,ut64 wordsz)617 R_API void r_meta_set_data_at(RAnal *a, ut64 addr, ut64 wordsz) {
618 r_return_if_fail (wordsz);
619 r_meta_set (a, R_META_TYPE_DATA, addr, wordsz, NULL);
620 }
621