Rizin
unix-like reverse engineering framework and cli tools
casm.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2009-2019 nibble <nibble.ds@gmail.com>
2 // SPDX-FileCopyrightText: 2009-2019 pancake <pancake@nopcode.org>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_types.h>
6 #include <rz_core.h>
7 #include <rz_asm.h>
8 
9 #define IFDBG if (0)
10 
11 static RzCoreAsmHit *find_addr(RzList *hits, ut64 addr);
12 static int prune_hits_in_hit_range(RzList *hits, RzCoreAsmHit *hit);
13 static int is_hit_inrange(RzCoreAsmHit *hit, ut64 start_range, ut64 end_range);
14 static int is_addr_in_range(ut64 start, ut64 end, ut64 start_range, ut64 end_range);
15 static void add_hit_to_sorted_hits(RzList *hits, ut64 addr, int len, ut8 is_valid);
17 
18 static int rcoreasm_address_comparator(RzCoreAsmHit *a, RzCoreAsmHit *b) {
19  if (a->addr == b->addr) {
20  return 0;
21  }
22  if (a->addr < b->addr) {
23  return -1;
24  }
25  return 1; /* a->addr > b->addr */
26 }
27 
28 RZ_API RzCoreAsmHit *rz_core_asm_hit_new(void) {
29  RzCoreAsmHit *hit = RZ_NEW0(RzCoreAsmHit);
30  if (!hit) {
31  return NULL;
32  }
33  hit->addr = -1;
34  hit->valid = false;
35  return hit;
36 }
37 
38 RZ_API RzList /*<RzCoreAsmHit *>*/ *rz_core_asm_hit_list_new(void) {
39  RzList *list = rz_list_new();
40  if (list) {
41  list->free = &rz_core_asm_hit_free;
42  }
43  return list;
44 }
45 
46 RZ_API void rz_core_asm_hit_free(void *_hit) {
47  RzCoreAsmHit *hit = _hit;
48  if (hit) {
49  if (hit->code) {
50  free(hit->code);
51  }
52  free(hit);
53  }
54 }
55 
56 RZ_API char *rz_core_asm_search(RzCore *core, const char *input) {
57  RzAsmCode *acode;
58  char *ret;
59  if (!(acode = rz_asm_massemble(core->rasm, input))) {
60  return NULL;
61  }
62  ret = rz_asm_code_get_hex(acode);
63  rz_asm_code_free(acode);
64  return ret;
65 }
66 
67 static const char *has_esil(RzCore *core, const char *name) {
70  rz_return_val_if_fail(core && core->analysis && name, NULL);
71  rz_list_foreach (core->analysis->plugins, iter, h) {
72  if (h->name && !strcmp(name, h->name)) {
73  return h->esil ? "Ae" : "A_";
74  }
75  }
76  return "__";
77 }
78 
79 RZ_API RzCmdStatus rz_core_asm_plugin_print(RzCore *core, RzAsmPlugin *ap, const char *arch, RzCmdStateOutput *state, const char *license) {
80  const char *feat2, *feat;
81  char bits[32];
82  PJ *pj = state->d.pj;
83  bits[0] = 0;
84  if (ap->bits == 27) {
85  strcat(bits, "27");
86  } else if (ap->bits == 0) {
87  strcat(bits, "any");
88  } else {
89  if (ap->bits & 4) {
90  strcat(bits, "4 ");
91  }
92  if (ap->bits & 8) {
93  strcat(bits, "8 ");
94  }
95  if (ap->bits & 16) {
96  strcat(bits, "16 ");
97  }
98  if (ap->bits & 32) {
99  strcat(bits, "32 ");
100  }
101  if (ap->bits & 64) {
102  strcat(bits, "64 ");
103  }
104  }
105  feat = "__";
106  if (ap->assemble && ap->disassemble) {
107  feat = "ad";
108  }
109  if (ap->assemble && !ap->disassemble) {
110  feat = "a_";
111  }
112  if (!ap->assemble && ap->disassemble) {
113  feat = "_d";
114  }
115  feat2 = has_esil(core, ap->name);
116  switch (state->mode) {
117  case RZ_OUTPUT_MODE_QUIET: {
118  rz_cons_println(ap->name);
119  break;
120  }
121  case RZ_OUTPUT_MODE_JSON: {
122  pj_ko(pj, ap->name);
123  pj_ks(pj, "bits", bits);
124  pj_ks(pj, "license", license);
125  pj_ks(pj, "description", ap->desc);
126  pj_ks(pj, "features", feat);
127  pj_end(pj);
128  break;
129  }
131  rz_cons_printf("%s%s %-9s %-11s %-7s %s",
132  feat, feat2, bits, ap->name, license, ap->desc);
133  if (ap->author) {
134  rz_cons_printf(" (by %s)", ap->author);
135  }
136  if (ap->version) {
137  rz_cons_printf(" v%s", ap->version);
138  }
139  rz_cons_newline();
140  break;
141  }
142  default: {
145  }
146  }
147  return RZ_CMD_STATUS_OK;
148 }
149 
151  int i;
152  RzAsm *a = core->rasm;
153  RzAsmPlugin *ap;
154  RzListIter *iter;
156  if (arch) {
157  rz_list_foreach (a->plugins, iter, ap) {
158  if (ap->cpus && !strcmp(arch, ap->name)) {
159  char *c = strdup(ap->cpus);
160  int n = rz_str_split(c, ',');
161  for (i = 0; i < n; i++) {
163  }
164  free(c);
165  break;
166  }
167  }
168  } else {
170  rz_list_foreach (a->plugins, iter, ap) {
171  const char *license = ap->license
172  ? ap->license
173  : "unknown";
174  status = rz_core_asm_plugin_print(core, ap, arch, state, license);
175  if (status != RZ_CMD_STATUS_OK) {
176  return status;
177  }
178  }
180  }
181  return RZ_CMD_STATUS_OK;
182 }
183 
184 // TODO: add support for byte-per-byte opcode search
185 RZ_API RzList /*<RzCoreAsmHit *>*/ *rz_core_asm_strsearch(RzCore *core, const char *input, ut64 from, ut64 to, int maxhits, int regexp, int everyByte, int mode) {
186  RzCoreAsmHit *hit;
187  RzAsmOp op;
188  RzList *hits;
189  ut64 at, toff = core->offset;
190  ut8 *buf;
191  int align = core->search->align;
192  RzRegex *rx = NULL;
193  char *tok, *tokens[1024], *code = NULL, *ptr;
194  int idx, tidx = 0, len = 0;
195  int tokcount, matchcount, count = 0;
196  int matches = 0;
197  const int addrbytes = core->io->addrbytes;
198 
199  if (!input || !*input) {
200  return NULL;
201  }
202 
203  char *inp = rz_str_trim_dup(input + 1);
204  char *inp_arg = strchr(inp, ' ');
205  if (inp_arg) {
206  *inp_arg++ = 0;
207  }
208  ut64 usrimm = rz_num_math(core->num, inp);
209  ut64 usrimm2 = inp_arg ? rz_num_math(core->num, inp_arg) : usrimm;
210  if (usrimm > usrimm2) {
211  eprintf("Error: /ci : Invalid range\n");
212  return NULL;
213  }
214 
215  if (core->blocksize < 8) {
216  eprintf("error: block size too small\n");
217  return NULL;
218  }
219  if (!(buf = (ut8 *)calloc(core->blocksize, 1))) {
220  return NULL;
221  }
222  if (!(ptr = strdup(input))) {
223  free(buf);
224  return NULL;
225  }
226  if (!(hits = rz_core_asm_hit_list_new())) {
227  free(buf);
228  free(ptr);
229  return NULL;
230  }
231  tokens[0] = NULL;
232  for (tokcount = 0; tokcount < RZ_ARRAY_SIZE(tokens) - 1; tokcount++) {
233  tok = strtok(tokcount ? NULL : ptr, ";");
234  if (!tok) {
235  break;
236  }
237  rz_str_trim(tok);
238  tokens[tokcount] = tok;
239  }
240  tokens[tokcount] = NULL;
242  char *opst = NULL;
243  for (at = from; at < to; at += core->blocksize) {
244  if (rz_cons_is_breaked()) {
245  break;
246  }
247  if (!rz_io_is_valid_offset(core->io, at, 0)) {
248  break;
249  }
250  (void)rz_io_read_at(core->io, at, buf, core->blocksize);
251  idx = 0, matchcount = 0;
252  while (addrbytes * (idx + 1) <= core->blocksize) {
253  ut64 addr = at + idx;
254  if (addr > to) {
255  break;
256  }
257  rz_asm_set_pc(core->rasm, addr);
258  if (mode == 'i') {
259  RzAnalysisOp analop = { 0 };
260  ut64 len = RZ_MIN(15, core->blocksize - idx);
262  idx++; // TODO: honor mininstrsz
263  continue;
264  }
265  ut64 val = analop.val; // Referenced value
266 
267  bool match = (val != UT64_MAX && val >= usrimm && val <= usrimm2);
268 
269  if (!match) {
270  for (size_t i = 0; i < 6; ++i) {
271  st64 v = analop.analysis_vals[i].imm;
272  match = (v != ST64_MAX && v >= usrimm && v <= usrimm2);
273  if (match) {
274  break;
275  }
276  }
277  }
278  if (!match) {
279  ut64 val = analop.disp;
280  match = (val != UT64_MAX && val >= usrimm && val <= usrimm2);
281  }
282  if (!match) {
283  st64 val = analop.ptr;
284  match = (val != ST64_MAX && val >= usrimm && val <= usrimm2);
285  }
286  if (match) {
287  if (!(hit = rz_core_asm_hit_new())) {
288  rz_list_purge(hits);
289  RZ_FREE(hits);
290  goto beach;
291  }
292  hit->addr = addr;
293  hit->len = analop.size; // idx + len - tidx;
294  if (hit->len == -1) {
296  goto beach;
297  }
298  rz_asm_disassemble(core->rasm, &op, buf + addrbytes * idx,
299  core->blocksize - addrbytes * idx);
300  hit->code = rz_str_new(rz_strbuf_get(&op.buf_asm));
301  rz_asm_op_fini(&op);
302  idx = (matchcount) ? tidx + 1 : idx + 1;
303  matchcount = 0;
304  rz_list_append(hits, hit);
305  continue;
306  }
308  idx++; // TODO: honor mininstrsz
309  continue;
310  } else if (mode == 'e') {
311  RzAnalysisOp analop = { 0 };
312  if (rz_analysis_op(core->analysis, &analop, addr, buf + idx, 15, RZ_ANALYSIS_OP_MASK_ESIL) < 1) {
313  idx++; // TODO: honor mininstrsz
314  continue;
315  }
316  // opsz = analop.size;
317  opst = strdup(rz_strbuf_get(&analop.esil));
319  } else {
320  if (!(len = rz_asm_disassemble(
321  core->rasm, &op,
322  buf + addrbytes * idx,
323  core->blocksize - addrbytes * idx))) {
324  idx = (matchcount) ? tidx + 1 : idx + 1;
325  matchcount = 0;
326  rz_asm_op_fini(&op);
327  continue;
328  }
329  // opsz = op.size;
330  opst = strdup(rz_strbuf_get(&op.buf_asm));
331  rz_asm_op_fini(&op);
332  }
333  if (opst) {
334  matches = strcmp(opst, "invalid") && strcmp(opst, "unaligned");
335  }
336  if (matches && tokens[matchcount]) {
337  if (mode == 'a') { // check for case sensitive
338  matches = !rz_str_ncasecmp(opst, tokens[matchcount], strlen(tokens[matchcount]));
339  } else if (!regexp) {
340  matches = strstr(opst, tokens[matchcount]) != NULL;
341  } else {
342  rx = rz_regex_new(tokens[matchcount], "es");
343  matches = rz_regex_exec(rx, opst, 0, 0, 0) == 0;
344  rz_regex_free(rx);
345  }
346  }
347  if (align && align > 1) {
348  if (addr % align) {
349  matches = false;
350  }
351  }
352  if (matches) {
353  code = rz_str_appendf(code, "%s; ", opst);
354  if (matchcount == tokcount - 1) {
355  if (tokcount == 1) {
356  tidx = idx;
357  }
358  if (!(hit = rz_core_asm_hit_new())) {
359  rz_list_purge(hits);
360  RZ_FREE(hits);
361  goto beach;
362  }
363  hit->addr = addr;
364  hit->len = idx + len - tidx;
365  if (hit->len == -1) {
367  goto beach;
368  }
369  code[strlen(code) - 2] = 0;
370  hit->code = strdup(code);
371  rz_list_append(hits, hit);
372  RZ_FREE(code);
373  matchcount = 0;
374  idx = tidx + 1;
375  if (maxhits) {
376  count++;
377  if (count >= maxhits) {
378  // eprintf ("Error: search.maxhits reached\n");
379  goto beach;
380  }
381  }
382  } else if (!matchcount) {
383  tidx = idx;
384  matchcount++;
385  idx += len;
386  } else {
387  matchcount++;
388  idx += len;
389  }
390  } else {
391  if (everyByte) {
392  idx = matchcount ? tidx + 1 : idx + 1;
393  } else {
394  idx += RZ_MAX(1, len);
395  }
396  RZ_FREE(code);
397  matchcount = 0;
398  }
399  RZ_FREE(opst);
400  }
401  }
403  rz_asm_set_pc(core->rasm, toff);
404 beach:
405  free(buf);
406  free(ptr);
407  free(code);
408  RZ_FREE(opst);
410  return hits;
411 }
412 
413 static void add_hit_to_sorted_hits(RzList *hits, ut64 addr, int len, ut8 is_valid) {
414  RzCoreAsmHit *hit = rz_core_asm_hit_new();
415  if (hit) {
416  IFDBG eprintf("*** Inserting instruction (valid?: %d): instr_addr: 0x%" PFMT64x " instr_len: %d\n", is_valid, addr, len);
417  hit->addr = addr;
418  hit->len = len;
419  hit->valid = is_valid;
420  hit->code = NULL;
422  }
423 }
424 
425 static void add_hit_to_hits(RzList *hits, ut64 addr, int len, ut8 is_valid) {
426  RzCoreAsmHit *hit = rz_core_asm_hit_new();
427  if (hit) {
428  IFDBG eprintf("*** Inserting instruction (valid?: %d): instr_addr: 0x%" PFMT64x " instr_len: %d\n", is_valid, addr, len);
429  hit->addr = addr;
430  hit->len = len;
431  hit->valid = is_valid;
432  hit->code = NULL;
433  if (!rz_list_append(hits, hit)) {
434  free(hit);
435  }
436  }
437 }
438 
440  RzCoreAsmHit hit = RZ_EMPTY;
441  hit.addr = addr;
442  hit.len = len;
443  hit.valid = is_valid;
444  return prune_hits_in_hit_range(hits, &hit);
445 }
446 
447 static int prune_hits_in_hit_range(RzList *hits, RzCoreAsmHit *hit) {
448  RzListIter *iter, *iter_tmp;
449  RzCoreAsmHit *to_check_hit;
450  int result = 0;
451  ut64 start_range, end_range;
452  if (!hit || !hits) {
453  return 0;
454  }
455  start_range = hit->addr;
456  end_range = hit->addr + hit->len;
457  rz_list_foreach_safe (hits, iter, iter_tmp, to_check_hit) {
458  if (to_check_hit && is_hit_inrange(to_check_hit, start_range, end_range)) {
459  IFDBG eprintf("Found hit that clashed (start: 0x%" PFMT64x
460  " - end: 0x%" PFMT64x " ), 0x%" PFMT64x " len: %d (valid: %d 0x%" PFMT64x
461  " - 0x%" PFMT64x ")\n",
462  start_range, end_range, to_check_hit->addr,
463  to_check_hit->len, to_check_hit->valid, to_check_hit->addr,
464  to_check_hit->addr + to_check_hit->len);
465  // XXX - could this be a valid decode instruction we are deleting?
466  rz_list_delete(hits, iter);
467  // iter->data = NULL;
468  to_check_hit = NULL;
469  result++;
470  }
471  }
472  return result;
473 }
474 
475 static RzCoreAsmHit *find_addr(RzList *hits, ut64 addr) {
476  // Find an address in the list of hits
477  RzListIter *addr_iter = NULL;
478  RzCoreAsmHit dummy_value;
479  dummy_value.addr = addr;
480  addr_iter = rz_list_find(hits, &dummy_value, ((RzListComparator)rcoreasm_address_comparator));
481  return rz_list_iter_get_data(addr_iter);
482 }
483 
484 static int handle_forward_disassemble(RzCore *core, RzList *hits, ut8 *buf, ut64 len, ut64 current_buf_pos, ut64 current_instr_addr, ut64 end_addr) {
485  RzCoreAsmHit *hit = NULL, *found_addr = NULL;
486  // forward disassemble from the current instruction up to the end address
487  ut64 temp_instr_addr = current_instr_addr;
488  ut64 tmp_current_buf_pos = current_buf_pos;
489  ut64 start_range = current_instr_addr;
490  ut64 end_range = end_addr;
491  ut64 temp_instr_len = 0;
492  ut64 start = 0, end = 0;
493  ut8 is_valid = false;
494  RzAsmOp op;
495 
496  if (end_addr < current_instr_addr) {
497  return end_addr;
498  }
499 
500  rz_asm_set_pc(core->rasm, current_instr_addr);
501  while (tmp_current_buf_pos < len && temp_instr_addr < end_addr) {
502  temp_instr_len = len - tmp_current_buf_pos;
503  IFDBG eprintf("Current position: %" PFMT64d " instr_addr: 0x%" PFMT64x "\n", tmp_current_buf_pos, temp_instr_addr);
504  temp_instr_len = rz_asm_disassemble(core->rasm, &op, buf + tmp_current_buf_pos, temp_instr_len);
505 
506  if (temp_instr_len == 0) {
507  is_valid = false;
508  temp_instr_len = 1;
509  } else {
510  is_valid = true;
511  }
512 
513  // check to see if addr exits
514  found_addr = find_addr(hits, temp_instr_addr);
515  start = temp_instr_addr;
516  end = temp_instr_addr + temp_instr_len;
517 
518  if (!found_addr) {
519  add_hit_to_sorted_hits(hits, temp_instr_addr, temp_instr_len, is_valid);
520  } else if (is_valid && !found_addr->valid && is_addr_in_range(start, end, start_range, end_range)) {
521  ut32 prune_results = 0;
522  prune_results = prune_hits_in_addr_range(hits, temp_instr_addr, temp_instr_len, is_valid);
523  add_hit_to_sorted_hits(hits, temp_instr_addr, temp_instr_len, is_valid);
524  if (prune_results) {
526  IFDBG eprintf("Pruned %u hits from list in fwd sweep.\n", prune_results);
527  } else {
528  RZ_FREE(hit);
529  }
530  }
531 
532  temp_instr_addr += temp_instr_len;
533  tmp_current_buf_pos += temp_instr_len;
534  }
535  return temp_instr_addr;
536 }
537 
538 #if 0
539 static int handle_disassembly_overlap(RzCore* core, RzList *hits, ut8* buf, int len, ut64 current_buf_pos, ut64 current_instr_addr ) {
540  // disassemble over lap means the current instruction decoded using the bytes in a previously decoded instruction
541  ut64 next_buf_pos = current_buf_pos,
542  end_addr = current_instr_addr + ( len - current_buf_pos - 1);
543 
544  /* Sub optimal method (e.g. easy) */
545  handle_forward_disassemble (core, hits, buf, len, current_buf_pos, current_instr_addr, end_addr );
546  next_buf_pos = current_buf_pos;
547  return next_buf_pos;
548 }
549 #endif
550 
551 static int is_addr_in_range(ut64 start, ut64 end, ut64 start_range, ut64 end_range) {
552  int result = false;
553  if (start == start_range) {
554  return true;
555  }
556  if (start < end && start_range < end_range) {
557  // ez cases
558  if (start_range <= start && start < end_range) {
559  result = true;
560  } else if (start_range < end && end < end_range) {
561  result = true;
562  } else if (start <= start_range && end_range < end) {
563  result = true;
564  }
565  // XXX - these cases need to be tested
566  // (long long) start_range < 0 < end_range
567  } else if (start_range > end_range) {
568  if (start < end) {
569  if (start < end_range) {
570  result = true;
571  } else if (end <= end_range) {
572  result = true;
573  } else if (start_range <= start) {
574  result = true;
575  } else if (start_range < end) {
576  result = true;
577  }
578  // (long long) start < 0 < end
579  } else {
580  if (end < end_range) {
581  result = true;
582  } else if (end <= end_range) {
583  result = true;
584  } else if (start_range <= start) {
585  result = true;
586  }
587  }
588  // XXX - these cases need to be tested
589  // (long long) start < 0 < end
590  } else if (start_range < end_range) {
591  if (start < end_range) {
592  result = true;
593  } else if (start <= start_range) {
594  result = true;
595  } else if (start_range < end) {
596  result = true;
597  }
598  }
599  return result;
600 }
601 
602 static int is_hit_inrange(RzCoreAsmHit *hit, ut64 start_range, ut64 end_range) {
603  int result = false;
604  if (hit) {
605  result = is_addr_in_range(hit->addr,
606  hit->addr + hit->len,
607  start_range, end_range);
608  }
609  return result;
610 }
611 
612 RZ_API RzList /*<RzCoreAsmHit *>*/ *rz_core_asm_bwdisassemble(RzCore *core, ut64 addr, int n, int len) {
613  RzAsmOp op;
614  // if (n > core->blocksize) n = core->blocksize;
615  ut64 at;
616  ut32 idx = 0, hit_count;
617  int numinstr, asmlen, ii;
618  const int addrbytes = core->io->addrbytes;
619  RzAsmCode *c;
621  if (!hits) {
622  return NULL;
623  }
624 
625  len = RZ_MIN(len - len % addrbytes, addrbytes * addr);
626  if (len < 1) {
627  rz_list_free(hits);
628  return NULL;
629  }
630 
631  ut8 *buf = (ut8 *)malloc(len);
632  if (!buf) {
633  rz_list_free(hits);
634  return NULL;
635  } else if (!hits) {
636  free(buf);
637  return NULL;
638  }
639  if (!rz_io_read_at(core->io, addr - len / addrbytes, buf, len)) {
640  rz_list_free(hits);
641  free(buf);
642  return NULL;
643  }
644 
645  for (idx = addrbytes; idx < len; idx += addrbytes) {
646  if (rz_cons_is_breaked()) {
647  break;
648  }
649  c = rz_asm_mdisassemble(core->rasm, buf + len - idx, idx);
650  if (strstr(c->assembly, "invalid") || strstr(c->assembly, ".byte")) {
652  continue;
653  }
654  numinstr = 0;
655  asmlen = strlen(c->assembly);
656  for (ii = 0; ii < asmlen; ii++) {
657  if (c->assembly[ii] == '\n') {
658  ++numinstr;
659  }
660  }
662  if (numinstr >= n || idx > 16 * n) { // assume average instruction length <= 16
663  break;
664  }
665  }
666  at = addr - idx / addrbytes;
667  rz_asm_set_pc(core->rasm, at);
668  for (hit_count = 0; hit_count < n; hit_count++) {
669  int instrlen = rz_asm_disassemble(core->rasm, &op,
670  buf + len - addrbytes * (addr - at), addrbytes * (addr - at));
671  add_hit_to_hits(hits, at, instrlen, true);
672  at += instrlen;
673  }
674  free(buf);
675  return hits;
676 }
677 
678 static RzList *rz_core_asm_back_disassemble_all(RzCore *core, ut64 addr, ut64 len, ut64 max_hit_count, ut32 extra_padding) {
680  RzCoreAsmHit dummy_value;
681  RzCoreAsmHit *hit = NULL;
682  RzAsmOp op;
683  ut8 *buf = (ut8 *)malloc(len + extra_padding);
684  int current_instr_len = 0;
685  ut64 current_instr_addr = addr,
686  current_buf_pos = len - 1,
687  hit_count = 0;
688 
689  memset(&dummy_value, 0, sizeof(RzCoreAsmHit));
690 
691  if (!hits || !buf) {
692  if (hits) {
693  rz_list_purge(hits);
694  free(hits);
695  }
696  free(buf);
697  return NULL;
698  }
699 
700  if (!rz_io_read_at(core->io, addr - (len + extra_padding), buf, len + extra_padding)) {
701  rz_list_purge(hits);
702  free(hits);
703  free(buf);
704  return NULL;
705  }
706 
707  if (len == 0) {
708  return hits;
709  }
710 
711  do {
712  if (rz_cons_is_breaked()) {
713  break;
714  }
715  // reset assembler
716  rz_asm_set_pc(core->rasm, current_instr_addr);
717  current_instr_len = len - current_buf_pos + extra_padding;
718  IFDBG eprintf("current_buf_pos: 0x%" PFMT64x ", current_instr_len: %d\n", current_buf_pos, current_instr_len);
719  current_instr_len = rz_asm_disassemble(core->rasm, &op, buf + current_buf_pos, current_instr_len);
721  hit->addr = current_instr_addr;
722  hit->len = current_instr_len;
723  hit->code = NULL;
725 
726  current_buf_pos--;
727  current_instr_addr--;
728  hit_count++;
729  } while (((int)current_buf_pos >= 0) && (int)(len - current_buf_pos) >= 0 && hit_count <= max_hit_count);
730 
731  free(buf);
732  return hits;
733 }
734 
735 static RzList *rz_core_asm_back_disassemble(RzCore *core, ut64 addr, int len, ut64 max_hit_count, ut8 disassmble_each_addr, ut32 extra_padding) {
736  RzList *hits;
737  ;
738  RzAsmOp op;
739  ut8 *buf = NULL;
740  ut8 max_invalid_b4_exit = 4,
741  last_num_invalid = 0;
742  int current_instr_len = 0;
743  ut64 current_instr_addr = addr,
744  current_buf_pos = 0,
745  next_buf_pos = len;
746 
747  RzCoreAsmHit dummy_value;
748  ut32 hit_count = 0;
749 
750  if (disassmble_each_addr) {
751  return rz_core_asm_back_disassemble_all(core, addr, len, max_hit_count, extra_padding + 1);
752  }
753 
754  hits = rz_core_asm_hit_list_new();
755  buf = malloc(len + extra_padding);
756  if (!hits || !buf) {
757  if (hits) {
758  rz_list_purge(hits);
759  free(hits);
760  }
761  free(buf);
762  return NULL;
763  }
764 
765  if (!rz_io_read_at(core->io, (addr + extra_padding) - len, buf, len + extra_padding)) {
766  rz_list_purge(hits);
767  free(hits);
768  free(buf);
769  return NULL;
770  }
771 
772  //
773  // XXX - This is a heavy handed approach without a
774  // an appropriate btree or hash table for storing
775  // hits, because are using:
776  // 1) Sorted RzList with many inserts and searches
777  // 2) Pruning hits to find the most optimal disassembly
778 
779  // greedy approach
780  // 1) Consume previous bytes
781  // 1a) Instruction is invalid (incr current_instr_addr)
782  // 1b) Disasm is perfect
783  // 1c) Disasm is underlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) short some bytes)
784  // 1d) Disasm is overlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) over some bytes)
785 
786  memset(&dummy_value, 0, sizeof(RzCoreAsmHit));
787  // disassemble instructions previous to current address, extra_padding can move the location of addr
788  // so we need to account for that with current_buf_pos
789  current_buf_pos = len - extra_padding - 1;
790  next_buf_pos = len + extra_padding - 1;
791  current_instr_addr = addr - 1;
792  do {
793  if (rz_cons_is_breaked()) {
794  break;
795  }
796  // reset assembler
797  rz_asm_set_pc(core->rasm, current_instr_addr);
798  current_instr_len = next_buf_pos - current_buf_pos;
799  current_instr_len = rz_asm_disassemble(core->rasm, &op, buf + current_buf_pos, current_instr_len);
800  IFDBG {
801  ut32 byte_cnt = current_instr_len ? current_instr_len : 1;
802  eprintf("current_instr_addr: 0x%" PFMT64x ", current_buf_pos: 0x%" PFMT64x ", current_instr_len: %d \n", current_instr_addr, current_buf_pos, current_instr_len);
803 
804  ut8 *hex_str = (ut8 *)rz_hex_bin2strdup(buf + current_buf_pos, byte_cnt);
805  eprintf("==== current_instr_bytes: %s ", hex_str);
806 
807  if (current_instr_len > 0) {
808  eprintf("op.buf_asm: %s\n", rz_strbuf_get(&op.buf_asm));
809  } else {
810  eprintf("op.buf_asm: <invalid>\n");
811  }
812  free(hex_str);
813  }
814  // disassembly invalid
815  if (current_instr_len == 0 || strstr(rz_strbuf_get(&op.buf_asm), "invalid")) {
816  if (current_instr_len == 0) {
817  current_instr_len = 1;
818  }
819  add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, /* is_valid */ false);
820  hit_count++;
821  last_num_invalid++;
822  // disassembly perfect
823  } else if (current_buf_pos + current_instr_len == next_buf_pos) {
824  // i think this may be the only case where an invalid instruction will be
825  // added because handle_forward_disassemble and handle_disassembly_overlap
826  // are only called in cases where a valid instruction has been found.
827  // and they are lazy, since they purge the hit list
828  ut32 purge_results = 0;
829  ut8 is_valid = true;
830  IFDBG eprintf(" handling underlap case: current_instr_addr: 0x%" PFMT64x ".\n", current_instr_addr);
831  purge_results = prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, /* is_valid */ true);
832  if (purge_results) {
833  handle_forward_disassemble(core, hits, buf, len, current_buf_pos + current_instr_len, current_instr_addr + current_instr_len, addr);
834  hit_count = rz_list_length(hits);
835  }
836  add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, is_valid);
837  // handle_forward_disassemble(core, hits, buf, len, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr/*end_addr*/);
838  hit_count++;
839  next_buf_pos = current_buf_pos;
840  last_num_invalid = 0;
841  // disassembly underlap
842  } else if (current_buf_pos + current_instr_len < next_buf_pos) {
843  prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, true);
844  add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, true);
845 
846  next_buf_pos = current_buf_pos;
847  handle_forward_disassemble(core, hits, buf, len - extra_padding, current_buf_pos + current_instr_len, current_instr_addr + current_instr_len, addr);
848  hit_count = rz_list_length(hits);
849  last_num_invalid = 0;
850  // disassembly overlap
851  } else if (current_buf_pos + current_instr_len > next_buf_pos) {
852  // ut64 value = handle_disassembly_overlap(core, hits, buf, len, current_buf_pos, current_instr_addr);
853  next_buf_pos = current_buf_pos;
854  hit_count = rz_list_length(hits);
855  last_num_invalid = 0;
856  }
857 
858  // walk backwards by one instruction
859  IFDBG eprintf(" current_instr_addr: 0x%" PFMT64x " current_instr_len: %d next_instr_addr: 0x%04" PFMT64x "\n",
860  current_instr_addr, current_instr_len, next_buf_pos);
861  IFDBG eprintf(" hit count: %d \n", hit_count);
862  current_instr_addr -= 1;
863  current_buf_pos -= 1;
864 
865  if (hit_count >= max_hit_count &&
866  (last_num_invalid >= max_invalid_b4_exit || last_num_invalid == 0)) {
867  break;
868  }
869  } while (((int)current_buf_pos >= 0) && (int)(len - current_buf_pos) >= 0);
870 
871  rz_asm_set_pc(core->rasm, addr);
872  free(buf);
873  return hits;
874 }
875 
876 RZ_API RzList /*<RzCoreAsmHit *>*/ *rz_core_asm_back_disassemble_instr(RzCore *core, ut64 addr, int len, ut32 hit_count, ut32 extra_padding) {
877  // extra padding to allow for additional disassembly on border buffer cases
878  ut8 disassmble_each_addr = false;
879  return rz_core_asm_back_disassemble(core, addr, len, hit_count, disassmble_each_addr, extra_padding);
880 }
881 
882 RZ_API RzList /*<RzCoreAsmHit *>*/ *rz_core_asm_back_disassemble_byte(RzCore *core, ut64 addr, int len, ut32 hit_count, ut32 extra_padding) {
883  // extra padding to allow for additional disassembly on border buffer cases
884  ut8 disassmble_each_addr = true;
885  return rz_core_asm_back_disassemble(core, addr, len, hit_count, disassmble_each_addr, extra_padding);
886 }
887 
888 /* Compute the len and the starting address
889  * when disassembling `nb` opcodes backward. */
890 RZ_API ut32 rz_core_asm_bwdis_len(RzCore *core, int *instr_len, ut64 *start_addr, ut32 nb) {
891  ut32 instr_run = 0;
892  RzCoreAsmHit *hit;
893  RzListIter *iter = NULL;
894  // TODO if length of nb instructions is larger than blocksize
895  RzList *hits = rz_core_asm_bwdisassemble(core, core->offset, nb, core->blocksize);
896  if (instr_len) {
897  *instr_len = 0;
898  }
899  if (hits && rz_list_length(hits) > 0) {
900  hit = rz_list_get_bottom(hits);
901  if (start_addr) {
902  *start_addr = hit->addr;
903  }
904  rz_list_foreach (hits, iter, hit) {
905  instr_run += hit->len;
906  }
907  if (instr_len) {
908  *instr_len = instr_run;
909  }
910  }
911  rz_list_free(hits);
912  return instr_run;
913 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
RZ_API void * rz_asm_code_free(RzAsmCode *acode)
Definition: acode.c:11
RZ_API char * rz_asm_code_get_hex(RzAsmCode *acode)
Definition: acode.c:68
static int analop(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask)
static bool is_valid(arm_reg reg)
RZ_API void rz_asm_op_fini(RzAsmOp *op)
Definition: aop.c:21
lzma_index ** i
Definition: index.h:629
ut16 val
Definition: armass64_const.h:6
RZ_API RzAsmCode * rz_asm_mdisassemble(RzAsm *a, const ut8 *buf, int len)
Definition: asm.c:743
RZ_API int rz_asm_set_pc(RzAsm *a, ut64 pc)
Definition: asm.c:533
RZ_API RzAsmCode * rz_asm_massemble(RzAsm *a, const char *assembly)
Definition: asm.c:814
RZ_API int rz_asm_disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len)
Definition: asm.c:543
int bits(struct state *s, int need)
Definition: blast.c:72
RZ_API char * rz_core_asm_search(RzCore *core, const char *input)
Definition: casm.c:56
RZ_API ut32 rz_core_asm_bwdis_len(RzCore *core, int *instr_len, ut64 *start_addr, ut32 nb)
Definition: casm.c:890
RZ_API RzList * rz_core_asm_back_disassemble_byte(RzCore *core, ut64 addr, int len, ut32 hit_count, ut32 extra_padding)
Definition: casm.c:882
static const char * has_esil(RzCore *core, const char *name)
Definition: casm.c:67
RZ_API RzList * rz_core_asm_strsearch(RzCore *core, const char *input, ut64 from, ut64 to, int maxhits, int regexp, int everyByte, int mode)
Definition: casm.c:185
static int is_addr_in_range(ut64 start, ut64 end, ut64 start_range, ut64 end_range)
Definition: casm.c:551
static int handle_forward_disassemble(RzCore *core, RzList *hits, ut8 *buf, ut64 len, ut64 current_buf_pos, ut64 current_instr_addr, ut64 end_addr)
Definition: casm.c:484
RZ_API RzCoreAsmHit * rz_core_asm_hit_new(void)
Definition: casm.c:28
#define IFDBG
Definition: casm.c:9
static int is_hit_inrange(RzCoreAsmHit *hit, ut64 start_range, ut64 end_range)
Definition: casm.c:602
static void add_hit_to_sorted_hits(RzList *hits, ut64 addr, int len, ut8 is_valid)
Definition: casm.c:413
static int prune_hits_in_addr_range(RzList *hits, ut64 addr, ut64 len, ut8 is_valid)
Definition: casm.c:439
RZ_API void rz_core_asm_hit_free(void *_hit)
Definition: casm.c:46
static RzCoreAsmHit * find_addr(RzList *hits, ut64 addr)
Definition: casm.c:475
static void add_hit_to_hits(RzList *hits, ut64 addr, int len, ut8 is_valid)
Definition: casm.c:425
RZ_API RzCmdStatus rz_core_asm_plugins_print(RzCore *core, const char *arch, RzCmdStateOutput *state)
Definition: casm.c:150
static int rcoreasm_address_comparator(RzCoreAsmHit *a, RzCoreAsmHit *b)
Definition: casm.c:18
RZ_API RzList * rz_core_asm_hit_list_new(void)
Definition: casm.c:38
static RzList * rz_core_asm_back_disassemble_all(RzCore *core, ut64 addr, ut64 len, ut64 max_hit_count, ut32 extra_padding)
Definition: casm.c:678
RZ_API RzList * rz_core_asm_bwdisassemble(RzCore *core, ut64 addr, int n, int len)
Definition: casm.c:612
RZ_API RzCmdStatus rz_core_asm_plugin_print(RzCore *core, RzAsmPlugin *ap, const char *arch, RzCmdStateOutput *state, const char *license)
Definition: casm.c:79
static int prune_hits_in_hit_range(RzList *hits, RzCoreAsmHit *hit)
Definition: casm.c:447
static RzList * rz_core_asm_back_disassemble(RzCore *core, ut64 addr, int len, ut64 max_hit_count, ut8 disassmble_each_addr, ut32 extra_padding)
Definition: casm.c:735
RZ_API RzList * rz_core_asm_back_disassemble_instr(RzCore *core, ut64 addr, int len, ut32 hit_count, ut32 extra_padding)
Definition: casm.c:876
RZ_API void rz_cmd_state_output_array_start(RzCmdStateOutput *state)
Mark the start of an array of elements in the output.
Definition: cmd_api.c:2558
RZ_API void rz_cmd_state_output_array_end(RzCmdStateOutput *state)
Mark the end of an array of elements in the output.
Definition: cmd_api.c:2572
RZ_API void rz_cons_newline(void)
Definition: cons.c:1274
RZ_API void rz_cons_break_pop(void)
Definition: cons.c:361
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
Definition: cons.c:357
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
RZ_API void rz_cons_println(const char *str)
Definition: cons.c:233
#define RZ_API
#define NULL
Definition: cris-opc.c:27
cs_arch arch
Definition: cstool.c:13
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 count
Definition: sflib.h:98
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 static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
uint32_t ut32
const char * v
Definition: dsignal.c:12
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
static char hex_str[]
Definition: utils.c:9
static int hit(RzSearchKeyword *kw, void *user, ut64 addr)
Definition: rz-find.c:58
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_BORROW RzListIter * rz_list_find(RZ_NONNULL const RzList *list, const void *p, RZ_NONNULL RzListComparator cmp)
Returns RzListIter element which matches via the RzListComparator.
Definition: list.c:620
RZ_API RZ_BORROW void * rz_list_get_bottom(RZ_NONNULL const RzList *list)
Returns the first element of the list.
Definition: list.c:467
RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_NONNULL RzListIter *iter)
Removes an entry in the list by using the RzListIter pointer.
Definition: list.c:162
RZ_API void * rz_list_iter_get_data(RzListIter *list)
returns the value stored in the list element
Definition: list.c:42
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API RZ_BORROW RzListIter * rz_list_add_sorted(RZ_NONNULL RzList *list, void *data, RZ_NONNULL RzListComparator cmp)
Adds an element to a sorted list via the RzListComparator.
Definition: list.c:518
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RZ_API void rz_list_purge(RZ_NONNULL RzList *list)
Empties the list without freeing the list pointer.
Definition: list.c:120
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
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")
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
int n
Definition: mipsasm.c:19
int idx
Definition: setup.py:197
RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op)
Definition: op.c:37
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
Definition: op.c:96
#define eprintf(x, y...)
Definition: rlcc.c:7
@ RZ_ANALYSIS_OP_MASK_DISASM
Definition: rz_analysis.h:445
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
@ RZ_ANALYSIS_OP_MASK_ESIL
Definition: rz_analysis.h:441
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
enum rz_cmd_status_t RzCmdStatus
@ RZ_CMD_STATUS_OK
command handler exited in the right way
Definition: rz_cmd.h:24
@ RZ_CMD_STATUS_NONEXISTINGCMD
command does not exist
Definition: rz_cmd.h:28
RZ_API char * rz_hex_bin2strdup(const ut8 *in, int len)
Definition: hex.c:415
RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, int len)
Definition: io.c:300
RZ_API bool rz_io_is_valid_offset(RzIO *io, ut64 offset, int hasperm)
Definition: ioutils.c:20
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
RZ_API ut64 rz_num_math(RzNum *num, const char *str)
Definition: unum.c:456
RZ_API PJ * pj_ko(PJ *j, const char *k)
Definition: pj.c:156
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
Definition: pj.c:170
RZ_API RzRegex * rz_regex_new(const char *pattern, const char *cflags)
Definition: regcomp.c:183
RZ_API int rz_regex_exec(const RzRegex *preg, const char *string, size_t nmatch, RzRegexMatch __pmatch[], int eflags)
Definition: regexec.c:149
RZ_API void rz_regex_free(RzRegex *)
Definition: regcomp.c:249
RZ_API char * rz_str_appendf(char *ptr, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
RZ_API char * rz_str_trim_dup(const char *str)
Definition: str_trim.c:78
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str)
Removes whitespace characters (space, tab, newline etc.) from the beginning and end of a string.
Definition: str_trim.c:190
RZ_API const char * rz_str_word_get0(const char *str, int idx)
Definition: str.c:598
RZ_API int rz_str_ncasecmp(const char *dst, const char *orig, size_t n)
Definition: str.c:129
RZ_API size_t rz_str_split(char *str, char ch)
Split string str in place by using ch as a delimiter.
Definition: str.c:406
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
@ RZ_OUTPUT_MODE_JSON
Definition: rz_types.h:40
@ RZ_OUTPUT_MODE_QUIET
Definition: rz_types.h:42
@ RZ_OUTPUT_MODE_STANDARD
Definition: rz_types.h:39
#define RZ_ARRAY_SIZE(x)
Definition: rz_types.h:300
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define RZ_EMPTY
Definition: rz_types_base.h:68
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10
#define RZ_MAX(x, y)
#define UT64_MAX
Definition: rz_types_base.h:86
#define ST64_MAX
Definition: rz_types_base.h:84
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr socklen_t static fromlen const void const struct sockaddr to
Definition: sfsocketcall.h:125
#define b(i)
Definition: sha256.c:42
#define c(i)
Definition: sha256.c:43
#define a(i)
Definition: sha256.c:41
#define h(i)
Definition: sha256.c:48
Definition: inftree9.h:24
Definition: engine.c:71
Definition: z80asm.h:102
Definition: rz_pj.h:12
RzList * plugins
Definition: rz_analysis.h:588
const char * desc
Definition: rz_asm.h:135
const char * license
Definition: rz_asm.h:136
const char * cpus
Definition: rz_asm.h:134
const char * name
Definition: rz_asm.h:130
const char * author
Definition: rz_asm.h:132
int(* assemble)(RzAsm *a, RzAsmOp *op, const char *buf)
Definition: rz_asm.h:142
int(* disassemble)(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len)
Definition: rz_asm.h:141
const char * version
Definition: rz_asm.h:133
Represent the output state of a command handler.
Definition: rz_cmd.h:91
RzSearch * search
Definition: rz_core.h:331
ut64 offset
Definition: rz_core.h:301
RzAsm * rasm
Definition: rz_core.h:323
RzAnalysis * analysis
Definition: rz_core.h:322
RzIO * io
Definition: rz_core.h:313
RzNum * num
Definition: rz_core.h:316
ut32 blocksize
Definition: rz_core.h:303
size_t addrbytes
Definition: rz_io.h:66
Definition: dis.h:43
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)