Rizin
unix-like reverse engineering framework and cli tools
rz-diff.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 deroad <wargio@libero.it>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_core.h>
5 #include <rz_io.h>
6 #include <rz_bin.h>
7 #include <rz_diff.h>
8 #include <rz_util.h>
9 #include <rz_main.h>
10 
11 #define MEGABYTE(x) (x << 20)
12 #define SAFE_STR_DEF(x, y) (x ? x : y)
13 #define SAFE_STR(x) (x ? x : "")
14 #define IF_STRCMP_S(ret, x, y) \
15  do { \
16  if ((x) != (y) && (!(x) || !(y))) { \
17  return !(y) ? 1 : -1; \
18  } else if ((x) && (y) && (ret = strcmp((x), (y)))) { \
19  return ret; \
20  } \
21  } while (0)
22 
23 typedef enum {
27 } DiffMode;
28 
29 typedef enum {
33 } DiffDistance;
34 
35 typedef enum {
50 } DiffType;
51 
52 typedef enum {
62 } DiffOption;
63 
64 typedef struct diff_screen_t {
65  int width;
66  int height;
68 
69 typedef struct diff_context_t {
76  bool show_time;
77  bool colors;
79  const char *architecture;
80  const char *input_a;
81  const char *input_b;
82  const char *file_a;
83  const char *file_b;
87 
88 typedef struct diff_io_t {
89  const char *filename;
91  RzIO *io;
93 
94 typedef struct diff_file_t {
95  /* const */
98  /* to free */
102 
103 typedef struct diff_function_t {
104  char *name;
105  int bits;
109 
110 typedef struct diff_colors_t {
111  const char *number;
112  const char *match;
113  const char *unmatch;
114  const char *legenda;
115  const char *reset;
117 
118 typedef struct diff_hex_view_t {
119  char *line;
133 
134 #define rz_diff_error(f, ...) \
135  RZ_LOG_ERROR("rz-diff: error, " f, ##__VA_ARGS__)
136 
137 #define rz_diff_error_ret(fail, f, ...) \
138  RZ_LOG_ERROR("rz-diff: error, " f, ##__VA_ARGS__); \
139  return (fail)
140 
141 #define rz_diff_error_opt(x, o, f, ...) \
142  (x)->option = o; \
143  RZ_LOG_ERROR("rz-diff: error, " f, ##__VA_ARGS__); \
144  return
145 
146 #define rz_diff_ctx_set(x, k, v) (x)->k = (v)
147 
148 #define rz_diff_set_def(x, d, v) \
149  do { \
150  if ((x) != (d)) { \
151  RZ_LOG_ERROR("rz-diff: error, invalid combination of arguments for '-%c' (expected " #d " but found something else)\n", c); \
152  return; \
153  } \
154  (x) = (v); \
155  } while (0)
156 
157 #define rz_diff_ctx_set_def(x, k, d, v) \
158  do { \
159  if ((x)->k != (d)) { \
160  rz_diff_error_opt(x, DIFF_OPT_UNKNOWN, "invalid combination of arguments for '-%c' (expected " #d " but found something else)\n", c); \
161  } \
162  (x)->k = (v); \
163  } while (0)
164 
165 #define rz_diff_ctx_set_val(x, k, d, v) \
166  do { \
167  if ((x)->k != (d)) { \
168  rz_diff_error_opt(x, DIFF_OPT_UNKNOWN, "invalid combination of arguments for '-%c' (expected " #d " but found something else)\n", c); \
169  } \
170  (x)->k = (v); \
171  } while (0)
172 
173 #define rz_diff_ctx_set_unsigned(x, k, i) \
174  do { \
175  (x)->k = strtoull((i), NULL, 0); \
176  if ((x)->k < 1) { \
177  rz_diff_error_opt(x, DIFF_OPT_UNKNOWN, "argument must be > 0\n"); \
178  } \
179  } while (0)
180 
181 #define rz_diff_ctx_add_evar(x, o) \
182  do { \
183  char *copy = rz_str_new(o); \
184  if (!copy || !rz_list_append((x)->evars, copy)) { \
185  free(copy); \
186  rz_diff_error_opt(x, DIFF_OPT_ERROR, "cannot add evar '%s' to list\n", o); \
187  } \
188  } while (0)
189 
190 #define rz_diff_ctx_set_dist(x, t) rz_diff_ctx_set_def(x, distance, DIFF_DISTANCE_UNKNOWN, t)
191 #define rz_diff_ctx_set_type(x, t) rz_diff_ctx_set_def(x, type, DIFF_TYPE_UNKNOWN, t)
192 #define rz_diff_ctx_set_mode(x, m) rz_diff_ctx_set_def(x, mode, DIFF_MODE_STANDARD, m)
193 #define rz_diff_ctx_set_opt(x, o) rz_diff_ctx_set_def(x, option, DIFF_OPT_UNKNOWN, o)
194 
195 static void rz_diff_show_help(bool usage_only) {
196  printf("Usage: rz-diff [options] <file0> <file1>\n");
197  if (usage_only) {
198  return;
199  }
200  printf(
201  " -a [arch] specify architecture plugin to use (x86, arm, ..)\n"
202  " -b [bits] specify register size for arch (16 (thumb), 32, 64, ..)\n"
203  " -d [algo] compute edit distance based on the choosen algorithm:\n"
204  " myers | Eugene W. Myers' O(ND) algorithm (no substitution)\n"
205  " leven | Levenshtein O(N^2) algorithm (with substitution)\n"
206  " -H hexadecimal visual mode\n"
207  " -h this help message\n"
208  " -j json output\n"
209  " -q quite output\n"
210  " -v show version information\n"
211  " -e [k=v] set an evaluable config variable\n"
212  " -A compare virtual and physical addresses\n"
213  " -B run 'aaa' when loading the bin\n"
214  " -C disable colors\n"
215  " -T show timestamp information\n"
216  " -S [WxH] sets the width and height of the terminal for visual mode\n"
217  " -0 [cmd] input for file0 when option -t 'commands' is given.\n"
218  " the same value will be set for file1, if -1 is not set.\n"
219  " -1 [cmd] input for file1 when option -t 'commands' is given.\n"
220  " -t [type] compute the difference between two files based on its type:\n"
221  " bytes | compares raw bytes in the files (only for small files)\n"
222  " lines | compares text files\n"
223  " functions | compares functions found in the files\n"
224  " classes | compares classes found in the files\n"
225  " command | compares command output returned when executed in both files\n"
226  " | requires -0 <cmd> and -1 <cmd> is optional\n"
227  " entries | compares entries found in the files\n"
228  " fields | compares fields found in the files\n"
229  " graphs | compares 2 functions and outputs in graphviz/dot format\n"
230  " | requires -0 <fcn name|offset> and -1 <fcn name|offset> is optional\n"
231  " imports | compares imports found in the files\n"
232  " libraries | compares libraries found in the files\n"
233  " sections | compares sections found in the files\n"
234  " strings | compares strings found in the files\n"
235  " symbols | compares symbols found in the files\n"
236  " palette colors can be changed by adding the following lines\n"
237  " inside the $HOME/.rizinrc file\n"
238  " ec diff.unknown blue | offset color\n"
239  " ec diff.match green | match color\n"
240  " ec diff.unmatch red | mismatch color\n"
241  "");
242 }
243 
244 static bool rz_diff_is_file(const char *file) {
245  if (IS_NULLSTR(file)) {
246  rz_diff_error_ret(false, "cannot open a file without a name.\n");
247  }
248  if (rz_file_is_directory(file)) {
249  rz_diff_error_ret(false, "cannot open directories (%s).\n", file);
250  }
251  return true;
252 }
253 
254 static void rz_diff_parse_arguments(int argc, const char **argv, DiffContext *ctx) {
255  const char *type = NULL;
256  const char *algorithm = NULL;
257  const char *screen = NULL;
258  memset((void *)ctx, 0, sizeof(DiffContext));
259  ctx->colors = true;
260  ctx->evars = rz_list_newf(free);
261 
262  if (!ctx->evars) {
263  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "cannot allocate list for evars");
264  return;
265  }
266 
267  RzGetopt opt;
268  int c;
269  rz_getopt_init(&opt, argc, argv, "hHjqvABCTa:b:e:d:t:0:1:S:");
270  while ((c = rz_getopt_next(&opt)) != -1) {
271  switch (c) {
272  case '0': rz_diff_ctx_set_def(ctx, input_a, NULL, opt.arg); break;
273  case '1': rz_diff_ctx_set_def(ctx, input_b, NULL, opt.arg); break;
274  case 'A': rz_diff_ctx_set_def(ctx, compare_addresses, false, true); break;
275  case 'B': rz_diff_ctx_set_def(ctx, analyze_all, false, true); break;
276  case 'C': rz_diff_ctx_set_def(ctx, colors, true, false); break;
277  case 'T': rz_diff_ctx_set_def(ctx, show_time, false, true); break;
278  case 'a': rz_diff_ctx_set_def(ctx, architecture, NULL, opt.arg); break;
279  case 'b': rz_diff_ctx_set_unsigned(ctx, arch_bits, opt.arg); break;
280  case 'd': rz_diff_set_def(algorithm, NULL, opt.arg); break;
281  case 'h': rz_diff_ctx_set_opt(ctx, DIFF_OPT_HELP); break;
282  case 'j': rz_diff_ctx_set_mode(ctx, DIFF_MODE_JSON); break;
283  case 'q': rz_diff_ctx_set_mode(ctx, DIFF_MODE_QUIET); break;
284  case 't': rz_diff_set_def(type, NULL, opt.arg); break;
285  case 'v': rz_diff_ctx_set_opt(ctx, DIFF_OPT_VERSION); break;
286  case 'S': rz_diff_set_def(screen, NULL, opt.arg); break;
287  case 'H': rz_diff_ctx_set_opt(ctx, DIFF_OPT_HEX_VISUAL); break;
288  case 'e': rz_diff_ctx_add_evar(ctx, opt.arg); break;
289  default:
290  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "unknown flag '%c'\n", c);
291  }
292  }
293 
294  if (ctx->option == DIFF_OPT_HELP ||
295  ctx->option == DIFF_OPT_VERSION) {
296  return;
297  }
298 
299  if (opt.ind >= argc || (argc - opt.ind) != 2) {
300  rz_diff_error_opt(ctx, DIFF_OPT_USAGE, "expected 2 files but got %d.\n", (argc - opt.ind));
301  }
302 
303  ctx->file_a = argv[opt.ind + 0];
304  ctx->file_b = argv[opt.ind + 1];
305 
306  if (!rz_diff_is_file(ctx->file_a) ||
307  !rz_diff_is_file(ctx->file_b)) {
308  ctx->option = DIFF_OPT_USAGE;
309  return;
310  }
311 
312  if (algorithm) {
313  if (type) {
314  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t argument is not compatible with -d.\n");
315  } else if (ctx->show_time) {
316  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -T argument is not compatible with -d.\n");
317  }
318 
320  if (!strcmp(algorithm, "myers")) {
322  } else if (!strcmp(algorithm, "leven")) {
324  } else {
325  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -d argument '%s' is not a recognized algorithm.\n", algorithm);
326  }
327  } else if (type) {
329 
330  if (!strcmp(type, "bytes")) {
332  } else if (!strcmp(type, "lines")) {
334  } else if (!strcmp(type, "functions")) {
335  if (ctx->input_a) {
336  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' does not support -0.\n", type);
337  } else if (ctx->input_b) {
338  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' does not support -1.\n", type);
339  }
340  ctx->option = DIFF_OPT_GRAPH;
342  } else if (!strcmp(type, "classes")) {
344  } else if (!strcmp(type, "command")) {
345  if (!ctx->input_a) {
346  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' requires -0 <command>.\n", type);
347  }
348  if (!ctx->input_b) {
349  ctx->input_b = ctx->input_a;
350  }
352  } else if (!strcmp(type, "entries")) {
354  } else if (!strcmp(type, "fields")) {
356  } else if (!strcmp(type, "graphs")) {
357  if (!ctx->input_a) {
358  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' requires -0 <fcn name|address>.\n", type);
359  } else if (ctx->input_a && !ctx->input_b) {
360  ctx->input_b = ctx->input_a;
361  }
362  ctx->option = DIFF_OPT_GRAPH;
364  } else if (!strcmp(type, "imports")) {
366  } else if (!strcmp(type, "libraries")) {
368  } else if (!strcmp(type, "sections")) {
370  } else if (!strcmp(type, "strings")) {
372  } else if (!strcmp(type, "symbols")) {
374  } else {
375  rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t argument '%s' is not a recognized type.\n", type);
376  }
377  } else if (screen) {
378  const char *hp = NULL;
379  if (!(hp = strchr(screen, 'x'))) {
380  rz_diff_error_opt(ctx, DIFF_OPT_USAGE, "invalid format for -S; example 120x20 where width=120 and height=20.\n");
381  }
382  ut64 height = strtoull(screen, NULL, 0);
383  ut64 width = strtoull(hp + 1, NULL, 0);
384  if (width < 1 || width > 0xFFFF || height < 1 || height > 0xFFFF) {
385  rz_diff_error_opt(ctx, DIFF_OPT_USAGE, "invalid format for -S; example 120x20 where width=120 and height=20.\n");
386  } else if (width < 20 || height < 120) {
387  rz_diff_error_opt(ctx, DIFF_OPT_USAGE, "Min width=120, Min height=20.\n");
388  }
389  ctx->screen.width = (int)width;
390  ctx->screen.height = (int)height;
391  } else if (ctx->option == DIFF_OPT_UNKNOWN) {
392  rz_diff_error_opt(ctx, DIFF_OPT_USAGE, "option -t or -d is required to be specified.\n");
393  }
394 }
395 
396 static void rz_diff_get_colors(DiffColors *dcolors, RzConsContext *ctx, bool colors) {
397  dcolors->number = colors ? ctx->pal.diff_unknown : "";
398  dcolors->match = colors ? ctx->pal.diff_match : "";
399  dcolors->unmatch = colors ? ctx->pal.diff_unmatch : Color_INVERT;
400  dcolors->legenda = colors ? ctx->pal.comment : "";
401  dcolors->reset = Color_RESET;
402 }
403 
404 static DiffIO *rz_diff_io_open(const char *file) {
405  RzIODesc *desc = NULL;
406  RzIO *io = NULL;
407  DiffIO *dio = NULL;
408 
409  dio = RZ_NEW0(DiffIO);
410  if (!dio) {
411  rz_diff_error("cannot allocate diff io\n");
412  goto rz_diff_io_open_end;
413  }
414 
415  io = rz_io_new();
416  if (!io) {
417  rz_diff_error("cannot allocate io\n");
418  goto rz_diff_io_open_end;
419  }
420 
421  desc = rz_io_open_nomap(io, file, RZ_PERM_R, 0);
422  if (!desc) {
423  rz_diff_error("cannot open file '%s'\n", file);
424  goto rz_diff_io_open_end;
425  }
426 
427  dio->filename = file;
428  dio->filesize = rz_io_desc_size(desc);
429  dio->io = io;
430  return dio;
431 
432 rz_diff_io_open_end:
434  rz_io_free(io);
435  free(dio);
436  return NULL;
437 }
438 
439 static void rz_diff_io_close(DiffIO *dio) {
440  if (!dio) {
441  return;
442  }
443  rz_io_desc_close(dio->io->desc);
444  rz_io_free(dio->io);
445  free(dio);
446 }
447 
448 /* This is terrible because can eat a lot of memory */
449 static ut8 *rz_diff_slurp_file(const char *file, size_t *size) {
450  ut8 *buffer = NULL;
451  ssize_t read = 0;
452  DiffIO *dio = NULL;
453 
454  dio = rz_diff_io_open(file);
455  if (!dio) {
456  goto rz_diff_slurp_file_end;
457  }
458 
459  if (dio->filesize > MEGABYTE(5)) {
460  rz_diff_error("cannot open file '%s' because its size is above 5Mb\n", file);
461  goto rz_diff_slurp_file_end;
462  }
463 
464  buffer = malloc(dio->filesize + 1);
465  if (!buffer) {
466  rz_diff_error("cannot allocate buffer\n");
467  goto rz_diff_slurp_file_end;
468  }
469  buffer[dio->filesize] = 0;
470 
471  read = rz_io_pread_at(dio->io, 0, buffer, dio->filesize);
472  if (read != dio->filesize) {
473  free(buffer);
474  buffer = NULL;
475  rz_diff_error("cannot read buffer correctly\n");
476  goto rz_diff_slurp_file_end;
477  }
478 
479  *size = dio->filesize;
480 
481 rz_diff_slurp_file_end:
482  rz_diff_io_close(dio);
483  return buffer;
484 }
485 
487  size_t a_size = 0;
488  size_t b_size = 0;
489  ut8 *a_buffer = NULL;
490  ut8 *b_buffer = NULL;
491  ut32 distance = 0;
492  double similarity = 0.0;
493 
494  if (!(a_buffer = rz_diff_slurp_file(ctx->file_a, &a_size))) {
495  goto rz_diff_calculate_distance_bad;
496  }
497 
498  if (!(b_buffer = rz_diff_slurp_file(ctx->file_b, &b_size))) {
499  goto rz_diff_calculate_distance_bad;
500  }
501 
502  switch (ctx->distance) {
503  case DIFF_DISTANCE_MYERS:
504  if (!rz_diff_myers_distance(a_buffer, a_size, b_buffer, b_size, &distance, &similarity)) {
505  rz_diff_error("failed to calculate distance with myers algorithm\n");
506  goto rz_diff_calculate_distance_bad;
507  }
508  break;
510  if (!rz_diff_levenstein_distance(a_buffer, a_size, b_buffer, b_size, &distance, &similarity)) {
511  rz_diff_error("failed to calculate distance with levenstein algorithm\n");
512  goto rz_diff_calculate_distance_bad;
513  }
514  break;
515  default:
516  rz_diff_error("unknown distance algorithm\n");
517  goto rz_diff_calculate_distance_bad;
518  }
519 
520  if (ctx->mode == DIFF_MODE_JSON) {
521  PJ *pj = pj_new();
522  if (!pj) {
523  rz_diff_error("failed to allocate json\n");
524  goto rz_diff_calculate_distance_bad;
525  }
526  pj_o(pj);
527  pj_kd(pj, "similarity", similarity);
528  pj_kn(pj, "distance", distance);
529  pj_end(pj);
530  printf("%s\n", pj_string(pj));
531  pj_free(pj);
532  } else if (ctx->mode == DIFF_MODE_QUIET) {
533  printf("%.3f\n", similarity);
534  printf("%d\n", distance);
535  } else {
536  // DIFF_MODE_STANDARD
537  printf("similarity: %.3f\n", similarity);
538  printf("distance: %d\n", distance);
539  }
540  free(a_buffer);
541  free(b_buffer);
542  return true;
543 
544 rz_diff_calculate_distance_bad:
545  free(a_buffer);
546  free(b_buffer);
547  return false;
548 }
549 
551  return rz_pvector_at(&cfile->binfiles, 0);
552 }
553 
554 static RzCoreFile *rz_diff_load_file_with_core(const char *filename, const char *architecture, ut32 arch_bits, RzList *evars, bool colors) {
555  RzCore *core = NULL;
556  RzCoreFile *cfile = NULL;
557  RzBinFile *bfile = NULL;
558  RzListIter *it;
559  char *config;
560 
561  core = rz_core_new();
562  if (!core) {
563  rz_diff_error("cannot allocate core\n");
564  goto rz_diff_load_file_with_core_fail;
565  }
566  rz_core_loadlibs(core, RZ_CORE_LOADLIBS_ALL);
567 
568  rz_config_set_i(core->config, "scr.color", colors ? 1 : 0);
569  rz_config_set_b(core->config, "scr.interactive", false);
570  rz_config_set_b(core->config, "cfg.debug", false);
571  core->print->scr_prompt = false;
572  cfile = rz_core_file_open(core, filename, 0, 0);
573  if (!cfile) {
574  rz_diff_error("cannot open file '%s'\n", filename);
575  goto rz_diff_load_file_with_core_fail;
576  }
577 
578  if (!rz_core_bin_load(core, NULL, UT64_MAX)) {
579  rz_diff_error("cannot load file '%s'\n", filename);
580  goto rz_diff_load_file_with_core_fail;
581  }
582 
583  if (!rz_core_bin_update_arch_bits(core)) {
584  rz_diff_error("cannot set architecture with bits\n");
585  goto rz_diff_load_file_with_core_fail;
586  }
587 
588  bfile = core_get_file(cfile);
589  if (!bfile) {
590  rz_diff_error("cannot get architecture with bits\n");
591  goto rz_diff_load_file_with_core_fail;
592  }
593 
594  if (rz_list_empty(bfile->o->maps)) {
595  rz_config_set_i(core->config, "io.va", false);
596  }
597 
598  if (architecture) {
599  rz_config_set(core->config, "asm.arch", architecture);
600  }
601 
602  if (arch_bits) {
603  rz_config_set_i(core->config, "asm.bits", arch_bits);
604  }
605 
606  rz_list_foreach (evars, it, config) {
607  rz_config_eval(core->config, config);
608  }
609 
610  return cfile;
611 
612 rz_diff_load_file_with_core_fail:
613  rz_core_free(core);
614  return NULL;
615 }
616 
617 static bool rz_diff_file_open(DiffFile *dfile, const char *filename) {
618  memset((void *)dfile, 0, sizeof(DiffFile));
619  RzBinOptions opt = { 0 };
620  RzBinFile *file = NULL;
621  RzBin *bin = NULL;
622  DiffIO *dio = NULL;
623 
624  dio = rz_diff_io_open(filename);
625  if (!dio) {
626  goto rz_diff_file_open_bad;
627  }
628 
629  bin = rz_bin_new();
630  if (!bin) {
631  rz_diff_error("cannot allocate bin\n");
632  goto rz_diff_file_open_bad;
633  }
634 
635  rz_io_bind(dio->io, &bin->iob);
636 
637  // TODO: no RzConfig ???
638  rz_bin_options_init(&opt, dio->io->desc->fd, 0, 0, false);
639  opt.obj_opts.elf_load_sections = true;
640  opt.obj_opts.elf_checks_sections = true;
641  opt.obj_opts.elf_checks_segments = true;
642  opt.sz = rz_io_desc_size(dio->io->desc);
643 
644  file = rz_bin_open_io(bin, &opt);
645  if (!file) {
646  rz_diff_error("cannot open bin file via io\n");
647  goto rz_diff_file_open_bad;
648  }
649 
651  dfile->file = file;
652  dfile->bin = bin;
653  dfile->dio = dio;
654  return true;
655 
656 rz_diff_file_open_bad:
657  rz_bin_free(bin);
658  rz_diff_io_close(dio);
659  return false;
660 }
661 
663  // plugin and file are freed by rz_bin_free
664  rz_bin_free(file->bin);
665  rz_diff_io_close(file->dio);
666 }
667 
668 #define rz_diff_file_get(df, n) ((df)->file->o->n)
669 
670 /**************************************** rzlists ***************************************/
671 
672 static const void *rz_diff_list_elem_at(const RzList *array, ut32 index) {
673  return rz_list_get_n(array, index);
674 }
675 
676 /**************************************** imports ***************************************/
677 
678 static ut32 import_hash(const RzBinImport *elem) {
679  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
680  hash ^= rz_diff_hash_data((const ut8 *)elem->bind, strlen(SAFE_STR(elem->bind)));
681  hash ^= rz_diff_hash_data((const ut8 *)elem->type, strlen(SAFE_STR(elem->type)));
682  return hash;
683 }
684 
685 static void import_stringify(const RzBinImport *elem, RzStrBuf *sb) {
686  rz_strbuf_setf(sb, "%-7s %-7s %s\n", SAFE_STR_DEF(elem->bind, RZ_BIN_BIND_UNKNOWN_STR),
688 }
689 
690 static int import_compare(const RzBinImport *a, const RzBinImport *b) {
691  int ret;
692  IF_STRCMP_S(ret, a->name, b->name);
693  IF_STRCMP_S(ret, a->bind, b->bind);
694  IF_STRCMP_S(ret, a->type, b->type);
695  return 0;
696 }
697 
698 static RzDiff *rz_diff_imports_new(DiffFile *dfile_a, DiffFile *dfile_b) {
699  RzList *list_a = NULL;
700  RzList *list_b = NULL;
701 
702  list_a = rz_diff_file_get(dfile_a, imports);
703  if (!list_a) {
704  rz_diff_error_ret(NULL, "cannot get imports from '%s'\n", dfile_a->dio->filename);
705  }
706 
707  list_b = rz_diff_file_get(dfile_b, imports);
708  if (!list_b) {
709  rz_diff_error_ret(NULL, "cannot get imports from '%s'\n", dfile_b->dio->filename);
710  }
711 
714 
715  RzDiffMethods methods = {
717  .elem_hash = (RzDiffMethodElemHash)import_hash,
720  .ignore = NULL,
721  };
722 
723  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
724 }
725 
726 /**************************************** symbols ***************************************/
727 
728 static ut32 symbol_hash_addr(const RzBinSymbol *elem) {
729  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
730  hash ^= rz_diff_hash_data((const ut8 *)elem->dname, strlen(elem->dname));
731  hash ^= rz_diff_hash_data((const ut8 *)elem->libname, strlen(elem->libname));
732  hash ^= rz_diff_hash_data((const ut8 *)elem->classname, strlen(elem->classname));
733  hash ^= (ut32)(elem->vaddr >> 32);
734  hash ^= (ut32)elem->vaddr;
735  hash ^= (ut32)(elem->paddr >> 32);
736  hash ^= (ut32)elem->paddr;
737  return hash;
738 }
739 
740 static int symbol_compare_addr(const RzBinSymbol *a, const RzBinSymbol *b) {
741  st64 ret;
742  IF_STRCMP_S(ret, a->classname, b->classname);
743  IF_STRCMP_S(ret, a->libname, b->libname);
744  IF_STRCMP_S(ret, a->dname, b->dname);
745  IF_STRCMP_S(ret, a->name, b->name);
746  ret = ((st64)b->paddr) - ((st64)a->paddr);
747  if (ret) {
748  return ret;
749  }
750  return ((st64)b->vaddr) - ((st64)a->vaddr);
751 }
752 
753 static void symbol_stringify_addr(const RzBinSymbol *elem, RzStrBuf *sb) {
754  rz_strbuf_setf(sb, "virt: 0x%016" PFMT64x " phys: 0x%016" PFMT64x " %s %s %s\n", elem->vaddr, elem->paddr, elem->libname, elem->classname, elem->name);
755 }
756 
757 static ut32 symbol_hash(const RzBinSymbol *elem) {
758  return rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
759 }
760 
761 static int symbol_compare(const RzBinSymbol *a, const RzBinSymbol *b) {
762  int ret;
763  IF_STRCMP_S(ret, a->name, b->name);
764  return 0;
765 }
766 
767 static void symbol_stringify(const RzBinSymbol *elem, RzStrBuf *sb) {
768  rz_strbuf_setf(sb, "%s %s %s\n", elem->libname, elem->classname, elem->name);
769 }
770 
771 static RzDiff *rz_diff_symbols_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr) {
772  RzList *list_a = NULL;
773  RzList *list_b = NULL;
774 
775  list_a = rz_diff_file_get(dfile_a, symbols);
776  if (!list_a) {
777  rz_diff_error_ret(NULL, "cannot get symbols from '%s'\n", dfile_a->dio->filename);
778  }
779 
780  list_b = rz_diff_file_get(dfile_b, symbols);
781  if (!list_b) {
782  rz_diff_error_ret(NULL, "cannot get symbols from '%s'\n", dfile_b->dio->filename);
783  }
784 
787 
788  RzDiffMethods methods = {
790  .elem_hash = (RzDiffMethodElemHash)(compare_addr ? symbol_hash_addr : symbol_hash),
792  .stringify = (RzDiffMethodStringify)(compare_addr ? symbol_stringify_addr : symbol_stringify),
793  .ignore = NULL,
794  };
795 
796  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
797 }
798 
799 /**************************************** strings ***************************************/
800 
801 static ut32 string_hash_addr(const RzBinString *elem) {
802  ut32 hash = rz_diff_hash_data((const ut8 *)elem->string, elem->size);
803  hash ^= (ut32)(elem->vaddr >> 32);
804  hash ^= (ut32)elem->vaddr;
805  hash ^= (ut32)(elem->paddr >> 32);
806  hash ^= (ut32)elem->paddr;
807  return hash;
808 }
809 
810 static int string_compare_addr(const RzBinString *a, const RzBinString *b) {
811  st64 ret;
812  ret = ((st64)b->size) - ((st64)a->size);
813  if (ret) {
814  return ret;
815  }
816  IF_STRCMP_S(ret, a->string, b->string);
817  ret = ((st64)b->paddr) - ((st64)a->paddr);
818  if (ret) {
819  return ret;
820  }
821  return ((st64)b->vaddr) - ((st64)a->vaddr);
822 }
823 
824 static void string_stringify_addr(const RzBinString *elem, RzStrBuf *sb) {
825  rz_strbuf_setf(sb, "virt: 0x%016" PFMT64x " phys: 0x%016" PFMT64x " %s\n", elem->vaddr, elem->paddr, elem->string);
826 }
827 
828 static ut32 string_hash(const RzBinString *elem) {
829  return rz_diff_hash_data((const ut8 *)elem->string, elem->size);
830 }
831 
832 static int string_compare(const RzBinString *a, const RzBinString *b) {
833  st64 ret;
834  ret = ((st64)b->size) - ((st64)a->size);
835  if (ret) {
836  return ret;
837  }
838  IF_STRCMP_S(ret, a->string, b->string);
839  return 0;
840 }
841 
842 static void string_stringify(const RzBinString *elem, RzStrBuf *sb) {
843  rz_strbuf_setf(sb, "%s\n", elem->string);
844 }
845 
846 static RzDiff *rz_diff_strings_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr) {
847  RzList *list_a = NULL;
848  RzList *list_b = NULL;
849 
850  list_a = (RzList *)rz_bin_object_get_strings(dfile_a->file->o);
851  if (!list_a) {
852  rz_diff_error_ret(NULL, "cannot get strings from '%s'\n", dfile_a->dio->filename);
853  }
854 
855  list_b = (RzList *)rz_bin_object_get_strings(dfile_b->file->o);
856  if (!list_b) {
857  rz_diff_error_ret(NULL, "cannot get strings from '%s'\n", dfile_b->dio->filename);
858  }
859 
862 
863  RzDiffMethods methods = {
865  .elem_hash = (RzDiffMethodElemHash)(compare_addr ? string_hash_addr : string_hash),
867  .stringify = (RzDiffMethodStringify)(compare_addr ? string_stringify_addr : string_stringify),
868  .ignore = NULL,
869  };
870 
871  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
872 }
873 
874 /**************************************** classes ***************************************/
875 
876 static ut32 class_hash_addr(const RzBinClass *elem) {
877  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
878  hash ^= rz_diff_hash_data((const ut8 *)elem->super, strlen(elem->super));
879  hash ^= (ut32)(elem->addr >> 32);
880  hash ^= (ut32)elem->addr;
881  return hash;
882 }
883 
884 static int class_compare_addr(const RzBinClass *a, const RzBinClass *b) {
885  int ret;
886  IF_STRCMP_S(ret, a->super, b->super);
887  IF_STRCMP_S(ret, a->name, b->name);
888  return a->addr - b->addr;
889 }
890 
891 static void class_stringify_addr(const RzBinClass *elem, RzStrBuf *sb) {
892  rz_strbuf_setf(sb, "0x%016" PFMT64x " %s %s\n", elem->addr, SAFE_STR(elem->super), elem->name);
893 }
894 
895 static ut32 class_hash(const RzBinClass *elem) {
896  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
897  hash ^= rz_diff_hash_data((const ut8 *)elem->super, strlen(elem->super));
898  return hash;
899 }
900 
901 static int class_compare(const RzBinClass *a, const RzBinClass *b) {
902  int ret;
903  IF_STRCMP_S(ret, a->super, b->super);
904  IF_STRCMP_S(ret, a->name, b->name);
905  return 0;
906 }
907 
908 static void class_stringify(const RzBinClass *elem, RzStrBuf *sb) {
909  rz_strbuf_setf(sb, "%s %s\n", SAFE_STR(elem->super), elem->name);
910 }
911 
912 static RzDiff *rz_diff_classes_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr) {
913  RzList *list_a = NULL;
914  RzList *list_b = NULL;
915 
916  list_a = rz_diff_file_get(dfile_a, classes);
917  if (!list_a) {
918  rz_diff_error_ret(NULL, "cannot get classes from '%s'\n", dfile_a->dio->filename);
919  }
920 
921  list_b = rz_diff_file_get(dfile_b, classes);
922  if (!list_b) {
923  rz_diff_error_ret(NULL, "cannot get classes from '%s'\n", dfile_b->dio->filename);
924  }
925 
928 
929  RzDiffMethods methods = {
931  .elem_hash = (RzDiffMethodElemHash)(compare_addr ? class_hash_addr : class_hash),
933  .stringify = (RzDiffMethodStringify)(compare_addr ? class_stringify_addr : class_stringify),
934  .ignore = NULL,
935  };
936 
937  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
938 }
939 
940 /**************************************** entries ***************************************/
941 
942 static ut32 entry_hash(const RzBinAddr *elem) {
943  ut32 hash = rz_diff_hash_data((const ut8 *)"entry", strlen("entry"));
944  hash ^= (ut32)(elem->vaddr >> 32);
945  hash ^= (ut32)elem->vaddr;
946  hash ^= (ut32)(elem->paddr >> 32);
947  hash ^= (ut32)elem->paddr;
948  hash ^= (ut32)elem->type;
949  return hash;
950 }
951 
952 static int entry_compare(const RzBinAddr *a, const RzBinAddr *b) {
953  st64 ret;
954  ret = ((st64)b->paddr) - ((st64)a->paddr);
955  if (ret) {
956  return ret;
957  }
958  ret = ((st64)b->vaddr) - ((st64)a->vaddr);
959  if (ret) {
960  return ret;
961  }
962  return b->type - a->type;
963 }
964 
965 static void entry_stringify(const RzBinAddr *elem, RzStrBuf *sb) {
966  const char *name = NULL;
967  switch (elem->type) {
969  name = "program";
970  break;
972  name = "main";
973  break;
975  name = "init";
976  break;
978  name = "fini";
979  break;
981  name = "tls";
982  break;
984  name = "preinit";
985  break;
986  default:
987  name = "unknown";
988  break;
989  }
990  rz_strbuf_setf(sb, "virt: 0x%016" PFMT64x " phys: 0x%016" PFMT64x " entry %s\n", elem->vaddr, elem->paddr, name);
991 }
992 
993 static RzDiff *rz_diff_entries_new(DiffFile *dfile_a, DiffFile *dfile_b) {
994  RzList *list_a = NULL;
995  RzList *list_b = NULL;
996 
997  list_a = rz_diff_file_get(dfile_a, entries);
998  if (!list_a) {
999  rz_diff_error_ret(NULL, "cannot get entries from '%s'\n", dfile_a->dio->filename);
1000  }
1001 
1002  list_b = rz_diff_file_get(dfile_b, entries);
1003  if (!list_b) {
1004  rz_diff_error_ret(NULL, "cannot get entries from '%s'\n", dfile_b->dio->filename);
1005  }
1006 
1009 
1010  RzDiffMethods methods = {
1012  .elem_hash = (RzDiffMethodElemHash)entry_hash,
1013  .compare = (RzDiffMethodCompare)entry_compare,
1014  .stringify = (RzDiffMethodStringify)entry_stringify,
1015  .ignore = NULL,
1016  };
1017 
1018  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
1019 }
1020 
1021 /**************************************** libraries ***************************************/
1022 
1023 static ut32 libs_hash(const char *elem) {
1024  return rz_diff_hash_data((const ut8 *)elem, strlen(elem));
1025 }
1026 
1027 static int libs_compare(const char *a, const char *b) {
1028  int ret;
1029  IF_STRCMP_S(ret, a, b);
1030  return 0;
1031 }
1032 
1033 static void libs_stringify(const char *elem, RzStrBuf *sb) {
1034  rz_strbuf_setf(sb, "%s\n", SAFE_STR(elem));
1035 }
1036 
1037 static RzDiff *rz_diff_libraries_new(DiffFile *dfile_a, DiffFile *dfile_b) {
1038  RzList *list_a = NULL;
1039  RzList *list_b = NULL;
1040 
1041  list_a = rz_diff_file_get(dfile_a, libs);
1042  if (!list_a) {
1043  rz_diff_error_ret(NULL, "cannot get libraries from '%s'\n", dfile_a->dio->filename);
1044  }
1045 
1046  list_b = rz_diff_file_get(dfile_b, libs);
1047  if (!list_b) {
1048  rz_diff_error_ret(NULL, "cannot get libraries from '%s'\n", dfile_b->dio->filename);
1049  }
1050 
1053 
1054  RzDiffMethods methods = {
1056  .elem_hash = (RzDiffMethodElemHash)libs_hash,
1057  .compare = (RzDiffMethodCompare)libs_compare,
1058  .stringify = (RzDiffMethodStringify)libs_stringify,
1059  .ignore = NULL,
1060  };
1061 
1062  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
1063 }
1064 
1065 /**************************************** sections ***************************************/
1066 
1067 static ut32 section_hash_addr(const RzBinSection *elem) {
1068  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
1069  hash ^= elem->perm;
1070  hash ^= (ut32)(elem->align >> 32);
1071  hash ^= (ut32)elem->align;
1072  hash ^= (ut32)(elem->vsize >> 32);
1073  hash ^= (ut32)elem->vsize;
1074  hash ^= (ut32)(elem->size >> 32);
1075  hash ^= (ut32)elem->size;
1076  hash ^= (ut32)(elem->vaddr >> 32);
1077  hash ^= (ut32)elem->vaddr;
1078  hash ^= (ut32)(elem->paddr >> 32);
1079  hash ^= (ut32)elem->paddr;
1080  return hash;
1081 }
1082 
1083 static int section_compare_addr(const RzBinSection *a, const RzBinSection *b) {
1084  st64 ret;
1085  IF_STRCMP_S(ret, a->name, b->name);
1086  ret = ((st64)b->size) - ((st64)a->size);
1087  if (ret) {
1088  return ret;
1089  }
1090  ret = ((st64)b->vsize) - ((st64)a->vsize);
1091  if (ret) {
1092  return ret;
1093  }
1094  ret = ((st64)b->paddr) - ((st64)a->paddr);
1095  if (ret) {
1096  return ret;
1097  }
1098  ret = ((st64)b->vaddr) - ((st64)a->vaddr);
1099  if (ret) {
1100  return ret;
1101  }
1102  ret = ((st64)b->perm) - ((st64)a->perm);
1103  if (ret) {
1104  return ret;
1105  }
1106  return ((st64)b->align) - ((st64)a->align);
1107 }
1108 
1109 static void section_stringify_addr(const RzBinSection *elem, RzStrBuf *sb) {
1110  char perm[5];
1111 
1112  perm[0] = elem->perm & RZ_PERM_SHAR ? 's' : '-';
1113  perm[1] = elem->perm & RZ_PERM_R ? 'r' : '-';
1114  perm[2] = elem->perm & RZ_PERM_W ? 'w' : '-';
1115  perm[3] = elem->perm & RZ_PERM_X ? 'x' : '-';
1116  perm[4] = 0;
1117 
1118  rz_strbuf_setf(sb, "virt: 0x%016" PFMT64x ":0x%04" PFMT64x " phys: 0x%016" PFMT64x ":0x%04" PFMT64x " align: 0x%08" PFMT64x " %s %s\n",
1119  elem->vaddr, elem->vsize, elem->paddr, elem->size, elem->align, perm, elem->name);
1120 }
1121 
1122 static ut32 section_hash(const RzBinSection *elem) {
1123  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
1124  hash ^= elem->perm;
1125  hash ^= (ut32)(elem->align >> 32);
1126  hash ^= (ut32)elem->align;
1127  return hash;
1128 }
1129 
1130 static int section_compare(const RzBinSection *a, const RzBinSection *b) {
1131  st64 ret;
1132  IF_STRCMP_S(ret, a->name, b->name);
1133  ret = ((st64)b->perm) - ((st64)a->perm);
1134  if (ret) {
1135  return ret;
1136  }
1137  return ((st64)b->align) - ((st64)a->align);
1138 }
1139 
1140 static void section_stringify(const RzBinSection *elem, RzStrBuf *sb) {
1141  char perm[5];
1142 
1143  perm[0] = elem->perm & RZ_PERM_SHAR ? 's' : '-';
1144  perm[1] = elem->perm & RZ_PERM_R ? 'r' : '-';
1145  perm[2] = elem->perm & RZ_PERM_W ? 'w' : '-';
1146  perm[3] = elem->perm & RZ_PERM_X ? 'x' : '-';
1147  perm[4] = 0;
1148 
1149  rz_strbuf_setf(sb, "align: 0x%08" PFMT64x " %s %s\n", elem->align, perm, elem->name);
1150 }
1151 
1152 static RzDiff *rz_diff_sections_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr) {
1153  RzList *list_a = NULL;
1154  RzList *list_b = NULL;
1155 
1156  list_a = rz_diff_file_get(dfile_a, sections);
1157  if (!list_a) {
1158  rz_diff_error_ret(NULL, "cannot get sections from '%s'\n", dfile_a->dio->filename);
1159  }
1160 
1161  list_b = rz_diff_file_get(dfile_b, sections);
1162  if (!list_b) {
1163  rz_diff_error_ret(NULL, "cannot get sections from '%s'\n", dfile_b->dio->filename);
1164  }
1165 
1168 
1169  RzDiffMethods methods = {
1171  .elem_hash = (RzDiffMethodElemHash)(compare_addr ? section_hash_addr : section_hash),
1173  .stringify = (RzDiffMethodStringify)(compare_addr ? section_stringify_addr : section_stringify),
1174  .ignore = NULL,
1175  };
1176 
1177  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
1178 }
1179 
1180 /**************************************** fields ***************************************/
1181 
1182 static ut32 field_hash_addr(const RzBinField *elem) {
1183  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
1184  hash ^= rz_diff_hash_data((const ut8 *)elem->type, strlen(SAFE_STR(elem->type)));
1185  hash ^= (ut32)(elem->paddr >> 32);
1186  hash ^= (ut32)elem->paddr;
1187  hash ^= (ut32)(elem->vaddr >> 32);
1188  hash ^= (ut32)elem->vaddr;
1189  return hash;
1190 }
1191 
1192 static int field_compare_addr(const RzBinField *a, const RzBinField *b) {
1193  st64 ret;
1194  IF_STRCMP_S(ret, a->name, b->name);
1195  IF_STRCMP_S(ret, a->type, b->type);
1196  ret = ((st64)b->size) - ((st64)a->size);
1197  if (ret) {
1198  return ret;
1199  }
1200  ret = ((st64)b->paddr) - ((st64)a->paddr);
1201  if (ret) {
1202  return ret;
1203  }
1204  return ((st64)b->vaddr) - ((st64)a->vaddr);
1205 }
1206 
1207 static void field_stringify_addr(const RzBinField *elem, RzStrBuf *sb) {
1208  rz_strbuf_setf(sb, "virt: 0x%016" PFMT64x " phys: 0x%016" PFMT64x " %-8s %s\n",
1209  elem->vaddr, elem->paddr, SAFE_STR(elem->type), elem->name);
1210 }
1211 
1212 static ut32 field_hash(const RzBinField *elem) {
1213  ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
1214  hash ^= rz_diff_hash_data((const ut8 *)elem->type, strlen(SAFE_STR(elem->type)));
1215  return hash;
1216 }
1217 
1218 static int field_compare(const RzBinField *a, const RzBinField *b) {
1219  int ret;
1220  IF_STRCMP_S(ret, a->name, b->name);
1221  IF_STRCMP_S(ret, a->type, b->type);
1222  return 0;
1223 }
1224 
1225 static void field_stringify(const RzBinField *elem, RzStrBuf *sb) {
1226  rz_strbuf_setf(sb, "%s %s\n", SAFE_STR(elem->type), elem->name);
1227 }
1228 
1229 static RzDiff *rz_diff_fields_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr) {
1230  RzList *list_a = NULL;
1231  RzList *list_b = NULL;
1232 
1233  list_a = rz_diff_file_get(dfile_a, fields);
1234  if (!list_a) {
1235  rz_diff_error_ret(NULL, "cannot get fields from '%s'\n", dfile_a->dio->filename);
1236  }
1237 
1238  list_b = rz_diff_file_get(dfile_b, fields);
1239  if (!list_b) {
1240  rz_diff_error_ret(NULL, "cannot get fields from '%s'\n", dfile_b->dio->filename);
1241  }
1242 
1245 
1246  RzDiffMethods methods = {
1248  .elem_hash = (RzDiffMethodElemHash)(compare_addr ? field_hash_addr : field_hash),
1250  .stringify = (RzDiffMethodStringify)(compare_addr ? field_stringify_addr : field_stringify),
1251  .ignore = NULL,
1252  };
1253 
1254  return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
1255 }
1256 
1257 /**************************************** commands ***************************************/
1258 
1259 static char *execute_command(const char *command, const char *filename, DiffContext *ctx) {
1260  RzCoreFile *cfile = rz_diff_load_file_with_core(filename, ctx->architecture, ctx->arch_bits, ctx->evars, ctx->colors);
1261  if (!cfile) {
1262  return NULL;
1263  }
1264 
1265  if (ctx->analyze_all && !rz_core_analysis_everything(cfile->core, false, NULL)) {
1266  rz_diff_error("cannot analyze binary '%s'\n", ctx->file_a);
1267  }
1268 
1269  char *output = rz_core_cmd_str(cfile->core, command);
1270  rz_core_free(cfile->core);
1271  return output;
1272 }
1273 
1275  char *output_a = NULL;
1276  char *output_b = NULL;
1277 
1278  output_a = execute_command(ctx->input_a, ctx->file_a, ctx);
1279  if (!output_a) {
1280  rz_diff_error_ret(NULL, "cannot execute command '%s' on file '%s'\n", ctx->input_a, ctx->file_a);
1281  }
1282 
1283  output_b = execute_command(ctx->input_b, ctx->file_b, ctx);
1284  if (!output_b) {
1285  free(output_a);
1286  rz_diff_error_ret(NULL, "cannot execute command '%s' on file '%s'\n", ctx->input_b, ctx->file_b);
1287  }
1288 
1289  RzDiff *diff = rz_diff_lines_new(output_a, output_b, NULL);
1290  free(output_a);
1291  free(output_b);
1292  return diff;
1293 }
1294 
1295 /**************************************** unified ***************************************/
1296 
1298  size_t a_size = 0;
1299  size_t b_size = 0;
1300  ut8 *a_buffer = NULL;
1301  ut8 *b_buffer = NULL;
1302  DiffFile dfile_a = { 0 };
1303  DiffFile dfile_b = { 0 };
1304  RzDiff *diff = NULL;
1305  bool result = false;
1306 
1307  if (ctx->type == DIFF_TYPE_BYTES ||
1308  ctx->type == DIFF_TYPE_LINES) {
1309  if (!(a_buffer = rz_diff_slurp_file(ctx->file_a, &a_size))) {
1310  goto rz_diff_unified_files_bad;
1311  }
1312 
1313  if (!(b_buffer = rz_diff_slurp_file(ctx->file_b, &b_size))) {
1314  goto rz_diff_unified_files_bad;
1315  }
1316  } else if (ctx->type != DIFF_TYPE_FUNCTIONS && ctx->type != DIFF_TYPE_COMMAND) {
1317  if (!rz_diff_file_open(&dfile_a, ctx->file_a)) {
1318  goto rz_diff_unified_files_bad;
1319  }
1320  if (!rz_diff_file_open(&dfile_b, ctx->file_b)) {
1321  goto rz_diff_unified_files_bad;
1322  }
1323  }
1324 
1325  switch (ctx->type) {
1326  case DIFF_TYPE_BYTES:
1327  diff = rz_diff_bytes_new(a_buffer, a_size, b_buffer, b_size, NULL);
1328  break;
1329  case DIFF_TYPE_CLASSES:
1330  diff = rz_diff_classes_new(&dfile_a, &dfile_b, ctx->compare_addresses);
1331  break;
1332  case DIFF_TYPE_COMMAND:
1333  diff = rz_diff_command_new(ctx);
1334  break;
1335  case DIFF_TYPE_ENTRIES:
1336  diff = rz_diff_entries_new(&dfile_a, &dfile_b);
1337  break;
1338  case DIFF_TYPE_FIELDS:
1339  diff = rz_diff_fields_new(&dfile_a, &dfile_b, ctx->compare_addresses);
1340  break;
1341  case DIFF_TYPE_IMPORTS:
1342  diff = rz_diff_imports_new(&dfile_a, &dfile_b);
1343  break;
1344  case DIFF_TYPE_LIBRARIES:
1345  diff = rz_diff_libraries_new(&dfile_a, &dfile_b);
1346  break;
1347  case DIFF_TYPE_LINES:
1348  diff = rz_diff_lines_new((const char *)a_buffer, (const char *)b_buffer, NULL);
1349  break;
1350  case DIFF_TYPE_SECTIONS:
1351  diff = rz_diff_sections_new(&dfile_a, &dfile_b, ctx->compare_addresses);
1352  break;
1353  case DIFF_TYPE_STRINGS:
1354  diff = rz_diff_strings_new(&dfile_a, &dfile_b, ctx->compare_addresses);
1355  break;
1356  case DIFF_TYPE_SYMBOLS:
1357  diff = rz_diff_symbols_new(&dfile_a, &dfile_b, ctx->compare_addresses);
1358  break;
1359  default:
1360  rz_diff_error("unknown type\n");
1361  goto rz_diff_unified_files_bad;
1362  }
1363 
1364  if (!diff) {
1365  goto rz_diff_unified_files_bad;
1366  }
1367 
1368  if (ctx->mode == DIFF_MODE_JSON) {
1369  PJ *pj = rz_diff_unified_json(diff, ctx->file_a, ctx->file_b, ctx->show_time);
1370  if (!pj) {
1371  goto rz_diff_unified_files_bad;
1372  }
1373  printf("%s\n", pj_string(pj));
1374  pj_free(pj);
1375  } else {
1376  // DIFF_MODE_STANDARD & DIFF_MODE_QUIET
1377  char *result = rz_diff_unified_text(diff, ctx->file_a, ctx->file_b, ctx->show_time, ctx->colors);
1378  if (!result) {
1379  goto rz_diff_unified_files_bad;
1380  }
1381  puts(result);
1382  free(result);
1383  }
1384 
1385  result = true;
1386 
1387 rz_diff_unified_files_bad:
1388  rz_diff_free(diff);
1389  rz_diff_file_close(&dfile_a);
1390  rz_diff_file_close(&dfile_b);
1391  free(a_buffer);
1392  free(b_buffer);
1393  return result;
1394 }
1395 
1396 /**************************************** graphs ***************************************/
1397 
1398 static bool convert_offset_from_input(RzCore *core, const char *input, ut64 *offset) {
1401  return true;
1402  }
1403 
1404  RzFlagItem *fi = rz_flag_get(core->flags, input);
1405  if (fi) {
1406  *offset = fi->offset;
1407  return true;
1408  }
1409 
1410  return false;
1411 }
1412 
1414  bool success = false;
1415  RzCoreFile *a = NULL;
1416  RzCoreFile *b = NULL;
1417 
1418  a = rz_diff_load_file_with_core(ctx->file_a, ctx->architecture, ctx->arch_bits, ctx->evars, ctx->colors);
1419  if (!a) {
1420  goto rz_diff_graphs_files_bad;
1421  }
1422 
1423  b = rz_diff_load_file_with_core(ctx->file_b, ctx->architecture, ctx->arch_bits, ctx->evars, ctx->colors);
1424  if (!b) {
1425  goto rz_diff_graphs_files_bad;
1426  }
1427 
1428  if (ctx->type == DIFF_TYPE_PLOTDIFF) {
1429  ut64 address_a = 0;
1430  ut64 address_b = 0;
1431 
1432  if (!convert_offset_from_input(a->core, ctx->input_a, &address_a)) {
1433  rz_diff_error("cannot convert '%s' into an offset\n", ctx->input_a);
1434  goto rz_diff_graphs_files_bad;
1435  }
1436 
1437  if (!convert_offset_from_input(b->core, ctx->input_b, &address_b)) {
1438  rz_diff_error("cannot convert '%s' into an offset\n", ctx->input_b);
1439  goto rz_diff_graphs_files_bad;
1440  }
1441 
1442  if (ctx->analyze_all) {
1443  if (!rz_core_analysis_everything(a->core, false, NULL)) {
1444  rz_diff_error("cannot analyze binary '%s'\n", ctx->file_a);
1445  goto rz_diff_graphs_files_bad;
1446  }
1447  if (!rz_core_analysis_everything(b->core, false, NULL)) {
1448  rz_diff_error("cannot analyze binary '%s'\n", ctx->file_b);
1449  goto rz_diff_graphs_files_bad;
1450  }
1451  } else {
1452  bool analyze_recursively = rz_config_get_i(a->core->config, "analysis.calls");
1453  if (!rz_core_analysis_function_add(a->core, NULL, address_a, analyze_recursively)) {
1454  rz_diff_error("cannot find function at '%s' in '%s' \n", ctx->input_a, ctx->file_a);
1455  goto rz_diff_graphs_files_bad;
1456  }
1457  if (!rz_core_analysis_function_add(b->core, NULL, address_b, analyze_recursively)) {
1458  rz_diff_error("cannot find function at '%s' in '%s' \n", ctx->input_b, ctx->file_b);
1459  goto rz_diff_graphs_files_bad;
1460  }
1461  }
1462 
1463  if (!rz_core_gdiff_function_2_files(a->core, b->core, address_a, address_b)) {
1464  rz_diff_error("cannot diff graphs with inputs '%s' with '%s'\n", ctx->input_a, ctx->input_b);
1465  goto rz_diff_graphs_files_bad;
1466  }
1467  rz_core_diff_show_function(a->core, b->core, address_a, ctx->mode == DIFF_MODE_JSON);
1468  } else {
1469  if (!rz_core_analysis_everything(a->core, false, NULL)) {
1470  rz_diff_error("cannot analyze binary '%s'\n", ctx->file_a);
1471  goto rz_diff_graphs_files_bad;
1472  }
1473  if (!rz_core_analysis_everything(b->core, false, NULL)) {
1474  rz_diff_error("cannot analyze binary '%s'\n", ctx->file_b);
1475  goto rz_diff_graphs_files_bad;
1476  }
1477  if (!rz_core_gdiff_2_files(a->core, b->core)) {
1478  rz_diff_error("cannot diff all graphs\n");
1479  goto rz_diff_graphs_files_bad;
1480  }
1481  rz_core_diff_show(a->core, b->core, ctx->mode == DIFF_MODE_JSON);
1482  }
1483 
1484  success = true;
1485 
1486 rz_diff_graphs_files_bad:
1487  rz_core_free(a ? a->core : NULL);
1488  rz_core_free(b ? b->core : NULL);
1489  return success;
1490 }
1491 
1492 /********************************************************************************/
1493 
1494 typedef enum diff_hex_len_t {
1499 
1500 static inline int diff_hexdump_partial(DiffHexView *hview, int hexlen, int lp, int lsize, const ut8 *bytes_a, const ut8 *bytes_b, ut64 address_a, ut64 address_b, ut64 size_a, ut64 size_b, ut64 pos, ssize_t read_a, ssize_t read_b, ssize_t skip_a, ssize_t skip_b) {
1501  const char *number = hview->colors.number;
1502  const char *match = hview->colors.match;
1503  const char *unmatch = hview->colors.unmatch;
1504  const char *reset = hview->colors.reset;
1505  ssize_t i;
1506  char *line = hview->line;
1507 
1508 #define P(x) (IS_PRINTABLE(x) ? x : '.')
1509 #define printline(fmt, ...) snprintf(line + lp, RZ_MAX(lsize - lp, 0), fmt, ##__VA_ARGS__)
1510  // write to buffer fileA offset + hex bytes
1511  lp += printline("%s0x%016" PFMT64x "%s | ", number, address_a + pos, reset);
1512  for (i = 0; i < hexlen && i < read_a; ++i) {
1513  if (pos + i >= size_a || pos + i < skip_a) {
1514  // if the byte is outside the range [0 - fileA size) then do not write any hex
1515  memset(line + lp, ' ', 3);
1516  lp += 3;
1517  } else if (i < read_b && pos + i >= skip_b) {
1518  // if the byte is inside the range [0 - fileA size) check bytes_b for match/mismatch
1519  const char *color = bytes_a[pos + i] == bytes_b[pos + i] ? match : unmatch;
1520  lp += printline("%s%02x%s ", color, bytes_a[pos + i], reset);
1521  } else {
1522  // if the byte is inside the range [0 - fileA size) but address_b
1523  // is outside [0 - fileB size) then is a mismatch
1524  lp += printline("%s%02x%s ", unmatch, bytes_a[pos + i], reset);
1525  }
1526  }
1527  if (i < hexlen) {
1528  // fill any missing space to have fileA bytes aligned
1529  memset(line + lp, ' ', (hexlen - i) * 3);
1530  lp += (hexlen - i) * 3;
1531  }
1532 
1533  // print now printable chars of the printed hex values
1534  lp += printline(" | ");
1535  for (i = 0; i < hexlen && i < read_a; ++i) {
1536  if (pos + i >= size_a || pos + i < skip_a) {
1537  // if the byte is outside the range [0 - fileA size) then do not write any hex
1538  line[lp] = ' ';
1539  lp++;
1540  } else if (i < read_b && pos + i >= skip_b) {
1541  // if the byte is inside the range [0 - fileA size) check bytes_b for match/mismatch
1542  const char *color = bytes_a[pos + i] == bytes_b[pos + i] ? match : unmatch;
1543  lp += printline("%s%c%s", color, P(bytes_a[pos + i]), reset);
1544  } else {
1545  // if the byte is inside the range [0 - fileA size) but address_b
1546  // is outside [0 - fileB size) then is a mismatch
1547  lp += printline("%s%c%s", unmatch, P(bytes_a[pos + i]), reset);
1548  }
1549  }
1550  if (i < hexlen) {
1551  // fill any missing space to have fileA bytes aligned
1552  memset(line + lp, ' ', (hexlen - i));
1553  lp += (hexlen - i);
1554  }
1555  return lp;
1556 #undef printline
1557 #undef P
1558 }
1559 
1560 static inline void diff_hexdump_line(DiffHexView *hview, DiffHexLen hlen, ut64 pos, ssize_t read_a, ssize_t read_b, ssize_t skip_a, ssize_t skip_b) {
1561  int width = hview->screen.width;
1562  int height = hview->screen.height;
1563  char *line = hview->line;
1564  const ut8 *buffer_a = hview->buffer_a;
1565  const ut8 *buffer_b = hview->buffer_b;
1566  ut64 address_a = hview->address_a;
1567  ut64 address_b = hview->address_b;
1568  int lp = 0;
1569  int lsize = width * height;
1570  int hexlen = 0;
1571 
1572  switch (hlen) {
1573  case DIFF_HEX_16:
1574  hexlen = 16;
1575  break;
1576  case DIFF_HEX_32:
1577  hexlen = 32;
1578  break;
1579  default:
1580  hexlen = 8;
1581  break;
1582  }
1583 
1584 #define printline(fmt, ...) snprintf(line + lp, RZ_MAX(lsize - lp, 0), fmt, ##__VA_ARGS__)
1585  lp = diff_hexdump_partial(hview, hexlen, 0, lsize, buffer_a, buffer_b, address_a, address_b, hview->size_a, hview->size_b, pos, read_a, read_b, skip_a, skip_b);
1586  lp += printline(" | ");
1587  lp = diff_hexdump_partial(hview, hexlen, lp, lsize, buffer_b, buffer_a, address_b, address_a, hview->size_b, hview->size_a, pos, read_b, read_a, skip_b, skip_a);
1588  lp += printline(" |");
1589 #undef printline
1590 }
1591 
1592 static inline int len_draw_hexdump(DiffHexView *hview) {
1593  int width = hview->screen.width;
1594  if (width >= (DIFF_HEX_32 * 2)) {
1595  return DIFF_HEX_32;
1596  } else if (width >= (DIFF_HEX_16 * 2)) {
1597  return DIFF_HEX_16;
1598  }
1599  return DIFF_HEX_8;
1600 }
1601 
1602 static inline int seek_min_shift(DiffHexView *hview) {
1603  int width = hview->screen.width;
1604  if (width >= (DIFF_HEX_32 * 2)) {
1605  return 5;
1606  } else if (width >= (DIFF_HEX_16 * 2)) {
1607  return 4;
1608  }
1609  return 3;
1610 }
1611 
1612 static inline int seek_min_value(DiffHexView *hview) {
1613  int width = hview->screen.width;
1614  if (width >= (DIFF_HEX_32 * 2)) {
1615  return 32;
1616  } else if (width >= (DIFF_HEX_16 * 2)) {
1617  return 16;
1618  }
1619  return 8;
1620 }
1621 
1622 static inline int offset_len(DiffHexView *hview) {
1623  ut64 filesize = RZ_MAX(hview->io_a->filesize, hview->io_b->filesize);
1624  if (filesize > UT32_MAX) {
1625  return 16;
1626  } else if (filesize > UT16_MAX) {
1627  return 8;
1628  }
1629  return 4;
1630 }
1631 
1632 static bool rz_diff_draw_tui(DiffHexView *hview, bool show_help) {
1633  ssize_t read_a = 0, read_b = 0;
1634  char *line = hview->line;
1635  int shift = 8, offlen = 16, xpos = 0;
1636  int width = hview->screen.width;
1637  int height = hview->screen.height;
1638  int lsize = width * height;
1639  DiffHexLen hlen = 0;
1640  DiffIO *io_a = hview->io_a;
1641  DiffIO *io_b = hview->io_b;
1642  ut64 filesize_a = hview->io_a->filesize;
1643  ut64 filesize_b = hview->io_b->filesize;
1644  ut64 max_rows = height - 2;
1645  ut64 skip_a = 0;
1646  ut64 skip_b = 0;
1647  RzConsCanvas *canvas = hview->canvas;
1648  const char *reset = hview->colors.reset;
1649  const char *legenda = hview->colors.legenda;
1650  const char *toolbar = NULL;
1651  bool utf8 = rz_cons_singleton()->use_utf8;
1652  const char *arrow_up = utf8 ? RUNE_ARROW_UP " " : "/\\";
1653  const char *arrow_down = utf8 ? RUNE_ARROW_DOWN " " : "\\/";
1654  const char *arrow_right = utf8 ? RUNE_ARROW_RIGHT " " : "> ";
1655  const char *arrow_left = utf8 ? RUNE_ARROW_LEFT " " : "< ";
1656 
1657  if (!line || !hview->buffer_a || !hview->buffer_b) {
1658  return false;
1659  }
1660 
1661  offlen = offset_len(hview);
1662  hlen = len_draw_hexdump(hview);
1663  xpos = RZ_MAX((width / 2) - hlen, 0);
1664 
1665  const char *p = NULL;
1666  const char *file_a = io_a->filename;
1667  const char *file_b = io_b->filename;
1668 
1669  p = io_a->filename;
1670  while ((p = strstr(file_a, RZ_SYS_DIR))) {
1671  file_a = p + 1;
1672  }
1673 
1674  p = io_b->filename;
1675  while ((p = strstr(file_b, RZ_SYS_DIR))) {
1676  file_b = p + 1;
1677  }
1678 
1679  if (hview->column_descr) {
1680  max_rows--;
1681  }
1682 
1683  if (hview->address_a > hview->size_a && (hview->address_a + hview->size_a) < hview->size_a) {
1684  // underflow
1685  ut64 size = hview->address_a + hview->size_a;
1686  ut64 offset_p = hview->size_a - size;
1687  read_a = rz_io_pread_at(io_a->io, 0, hview->buffer_a + offset_p, size);
1688  if (read_a > 0) {
1689  // include also excluded bytes from underflow
1690  read_a += offset_p;
1691  skip_a = offset_p;
1692  }
1693  } else {
1694  read_a = rz_io_pread_at(io_a->io, hview->address_a, hview->buffer_a, hview->size_a);
1695  }
1696 
1697  if (hview->address_b > hview->size_b && (hview->address_b + hview->size_b) < hview->size_b) {
1698  // underflow
1699  ut64 size = hview->address_b + hview->size_b;
1700  ut64 offset_p = hview->size_b - size;
1701  read_b = rz_io_pread_at(io_b->io, 0, hview->buffer_b + offset_p, size);
1702  if (read_b > 0) {
1703  // include also excluded bytes from underflow
1704  read_b += offset_p;
1705  skip_b = offset_p;
1706  }
1707  } else {
1708  read_b = rz_io_pread_at(io_b->io, hview->address_b, hview->buffer_b, hview->size_b);
1709  }
1710 
1712  rz_cons_clear();
1713  rz_cons_canvas_clear(canvas);
1714  shift = seek_min_shift(hview);
1715  for (ut64 h = 0, pos = 0; h < max_rows; ++h) {
1716  // draw hexadecimal values
1717  pos = h << shift;
1718  diff_hexdump_line(hview, hlen, pos, read_a - pos, read_b - pos, skip_a, skip_b);
1719  rz_cons_canvas_gotoxy(canvas, xpos, h + (hview->column_descr ? 2 : 1));
1720  rz_cons_canvas_write(canvas, line);
1721  }
1722 
1723  switch (len_draw_hexdump(hview)) {
1724  case DIFF_HEX_32: toolbar = " 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"; break;
1725  case DIFF_HEX_16: toolbar = " 0 1 2 3 4 5 6 7 8 9 A B C D E F"; break;
1726  default: toolbar = " 0 1 2 3 4 5 6 7"; break;
1727  }
1728 
1729  rz_cons_canvas_box(canvas, 0, 0, width, height - 1, reset);
1730  if (hview->column_descr) {
1731  rz_cons_canvas_gotoxy(canvas, xpos + 21, 1);
1732  rz_cons_canvas_write(canvas, toolbar);
1733  rz_cons_canvas_gotoxy(canvas, xpos, 0);
1734  } else {
1735  rz_cons_canvas_gotoxy(canvas, xpos, 0);
1736  }
1737  snprintf(line, lsize, " [%*" PFMT64x "]( %.42s )", offlen, filesize_a, file_a);
1738  rz_cons_canvas_write(canvas, line);
1739 
1740  if (hview->column_descr) {
1741  rz_cons_canvas_gotoxy(canvas, xpos + hlen + 22, 1);
1742  rz_cons_canvas_write(canvas, toolbar);
1743  rz_cons_canvas_gotoxy(canvas, xpos + hlen, 0);
1744  } else {
1745  rz_cons_canvas_gotoxy(canvas, xpos + hlen, 0);
1746  }
1747  snprintf(line, lsize, " [%*" PFMT64x "]( %.42s )", offlen, filesize_b, file_b);
1748  rz_cons_canvas_write(canvas, line);
1749 
1750  // clang-format off
1751  toolbar = " "
1752  "%s1 2%s -/+0x%x | "
1753  "%sZ A%s file0 +/-1 | "
1754  "%sC D%s file1 +/-1 | "
1755  "%sG B%s end/begin | "
1756  "%sN M%s next/prev | "
1757  "%s%s%s%s +/-%u | "
1758  "%s%s%s%s +/-1 | "
1759  "%s:%s seek";
1760  snprintf(line, lsize, toolbar
1761  , legenda, reset, (1 << shift) * max_rows
1762  , legenda, reset
1763  , legenda, reset
1764  , legenda, reset
1765  , legenda, reset
1766  , legenda, arrow_down, arrow_up, reset, 1 << shift
1767  , legenda, arrow_left, arrow_right, reset
1768  , legenda, reset);
1769  // clang-format on
1770 
1771  rz_cons_canvas_gotoxy(canvas, 0, height);
1772  rz_cons_canvas_write(canvas, line);
1773 
1774  if (show_help) {
1775  rz_cons_canvas_fill(canvas, 4, 2, 56, 16, ' ');
1776  rz_cons_canvas_box(canvas, 4, 2, 56, 16, legenda);
1777 
1778  snprintf(line, lsize, "%sHelp page%s\n", legenda, reset);
1779  rz_cons_canvas_gotoxy(canvas, 6, 3);
1780  rz_cons_canvas_write(canvas, line);
1781 
1782  snprintf(line, lsize, "%s1 2%s increase/decrease the offsets by 0x%x\n", legenda, reset, (1 << shift) * (height - 2));
1783  rz_cons_canvas_gotoxy(canvas, 6, 5);
1784  rz_cons_canvas_write(canvas, line);
1785 
1786  snprintf(line, lsize, "%sZ A%s increase/decrease the offset of the file0 by 1\n", legenda, reset);
1787  rz_cons_canvas_gotoxy(canvas, 6, 6);
1788  rz_cons_canvas_write(canvas, line);
1789 
1790  snprintf(line, lsize, "%sC D%s increase/decrease the offset of the file1 by 1\n", legenda, reset);
1791  rz_cons_canvas_gotoxy(canvas, 6, 7);
1792  rz_cons_canvas_write(canvas, line);
1793 
1794  snprintf(line, lsize, "%sN M%s next/previous difference\n", legenda, reset);
1795  rz_cons_canvas_gotoxy(canvas, 6, 8);
1796  rz_cons_canvas_write(canvas, line);
1797 
1798  snprintf(line, lsize, "%sG B%s seek to end/begin\n", legenda, reset);
1799  rz_cons_canvas_gotoxy(canvas, 6, 9);
1800  rz_cons_canvas_write(canvas, line);
1801 
1802  snprintf(line, lsize, "%s9%s sets both offsets to a common value\n", legenda, reset);
1803  rz_cons_canvas_gotoxy(canvas, 6, 10);
1804  rz_cons_canvas_write(canvas, line);
1805 
1806  snprintf(line, lsize, "%s0%s shows/hides the column legenda\n", legenda, reset);
1807  rz_cons_canvas_gotoxy(canvas, 6, 11);
1808  rz_cons_canvas_write(canvas, line);
1809 
1810  snprintf(line, lsize, "%s%s %s%s increase/decrease both offsets by %u\n", legenda, arrow_down, arrow_up, reset, 1 << shift);
1811  rz_cons_canvas_gotoxy(canvas, 6, 12);
1812  rz_cons_canvas_write(canvas, line);
1813 
1814  snprintf(line, lsize, "%s%s %s%s increase/decrease both offsets by 1\n", legenda, arrow_left, arrow_right, reset);
1815  rz_cons_canvas_gotoxy(canvas, 6, 13);
1816  rz_cons_canvas_write(canvas, line);
1817 
1818  snprintf(line, lsize, "%s:%s seek at offset (relative via +-)\n", legenda, reset);
1819  rz_cons_canvas_gotoxy(canvas, 6, 14);
1820  rz_cons_canvas_write(canvas, line);
1821 
1822  snprintf(line, lsize, "%s3%s file0 seek at offset (relative via +-)\n", legenda, reset);
1823  rz_cons_canvas_gotoxy(canvas, 6, 15);
1824  rz_cons_canvas_write(canvas, line);
1825 
1826  snprintf(line, lsize, "%s4%s file1 seek at offset (relative via +-)\n", legenda, reset);
1827  rz_cons_canvas_gotoxy(canvas, 6, 16);
1828  rz_cons_canvas_write(canvas, line);
1829  }
1830 
1831  rz_cons_canvas_print(canvas);
1832  rz_cons_flush();
1833 
1834  // allow to refresh the terminal
1835  // before printing again the ui
1836  rz_sys_usleep(200);
1837  return true;
1838 }
1839 
1840 static char *visual_prompt(DiffHexView *hview, const char *prompt) {
1841  char buf[1024];
1842  rz_cons_gotoxy(0, hview->screen.height);
1843  rz_cons_clear_line(0);
1844  rz_cons_printf("%s%s ", hview->colors.reset, prompt);
1845  rz_line_set_prompt(":> ");
1846  rz_cons_flush();
1847  rz_cons_fgets(buf, sizeof(buf), 0, NULL);
1848  if (*buf) {
1849  return strdup(buf);
1850  }
1851  return NULL;
1852 }
1853 
1854 static void prompt_offset_and_seek(DiffHexView *hview, ut64 minseek) {
1855  char *value = visual_prompt(hview, " you can input an absolute offset or a relative offset by adding the prefix + or -\n offset");
1856  if (value) {
1857  const char *p = rz_str_trim_head_ro(value);
1858  if (!IS_DIGIT(*p) && *p != '-' && *p != '+') {
1859  free(value);
1860  return;
1861  }
1862  st64 number = strtoll((*p == '+' || *p == '-') ? p + 1 : p, NULL, 0);
1863  if (*p == '-') {
1864  hview->address_a -= number;
1865  hview->address_b -= number;
1866  } else if (*p == '+') {
1867  hview->address_a += number;
1868  hview->address_b += number;
1869  } else {
1870  hview->address_a = number;
1871  hview->address_b = number;
1872  }
1873  }
1874  free(value);
1875 }
1876 
1877 static void prompt_offset_and_seek_file(DiffHexView *hview, ut64 minseek, bool is_file0) {
1878  char *value = visual_prompt(hview, " you can input an absolute offset or a relative offset by adding the prefix + or -\n offset");
1879  if (value) {
1880  const char *p = rz_str_trim_head_ro(value);
1881  if (!IS_DIGIT(*p) && *p != '-' && *p != '+') {
1882  free(value);
1883  return;
1884  }
1885  st64 number = strtoll((*p == '+' || *p == '-') ? p + 1 : p, NULL, 0);
1886  if (*p == '-') {
1887  if (is_file0) {
1888  hview->address_a -= number;
1889  } else {
1890  hview->address_b -= number;
1891  }
1892  } else if (*p == '+') {
1893  if (is_file0) {
1894  hview->address_a += number;
1895  } else {
1896  hview->address_b += number;
1897  }
1898  } else {
1899  if (is_file0) {
1900  hview->address_a = number;
1901  } else {
1902  hview->address_b = number;
1903  }
1904  }
1905  }
1906  free(value);
1907 }
1908 
1909 static void find_next_diff(DiffHexView *hview, ut64 seek) {
1910  if (!hview->buffer_a || !hview->buffer_b) {
1911  return;
1912  }
1913 
1914  DiffIO *io_a = hview->io_a;
1915  DiffIO *io_b = hview->io_b;
1916  ssize_t read_a = 0, read_b = 0;
1917  ssize_t minread = 0, minseek = 0;
1918  ut64 address_a = hview->address_a + seek;
1919  ut64 address_b = hview->address_b + seek;
1920  ut64 minsize = RZ_MIN(hview->size_a, hview->size_b);
1921  if (RZ_MIN(io_a->filesize, io_b->filesize) < seek) {
1922  hview->address_a = 0;
1923  hview->address_b = 0;
1924  return;
1925  }
1926  do {
1927  read_a = rz_io_pread_at(io_a->io, address_a, hview->buffer_a, minsize);
1928  read_b = rz_io_pread_at(io_b->io, address_b, hview->buffer_b, minsize);
1929  if (read_a < 1 || read_b < 1) {
1930  break;
1931  }
1932  minread = RZ_MIN(read_a, read_b);
1933  if (minread != minsize && !memcmp(hview->buffer_a, hview->buffer_b, minread)) {
1934  address_a += RZ_MAX(minread - seek, 0);
1935  address_b += RZ_MAX(minread - seek, 0);
1936  break;
1937  } else if (minread == minsize && !memcmp(hview->buffer_a, hview->buffer_b, minsize)) {
1938  address_a += minsize;
1939  address_b += minsize;
1940  continue;
1941  }
1942  minread = RZ_MIN(minsize, minread);
1943  minseek = RZ_MIN(seek, minread);
1944  for (ssize_t i = 0; i < minread; i += minseek) {
1945  if (memcmp(&hview->buffer_a[i], &hview->buffer_b[i], minseek)) {
1946  hview->address_a = address_a;
1947  hview->address_b = address_b;
1948  return;
1949  }
1950  address_a += minseek;
1951  address_b += minseek;
1952  }
1953  } while (1);
1954 
1955  if (address_a >= io_a->filesize) {
1956  address_a = io_a->filesize - seek;
1957  }
1958 
1959  if (address_b >= io_b->filesize) {
1960  address_b = io_b->filesize - seek;
1961  }
1962 
1963  hview->address_a = address_a;
1964  hview->address_b = address_b;
1965 }
1966 
1967 static void find_prev_diff(DiffHexView *hview, ut64 seek) {
1968  if (!hview->buffer_a || !hview->buffer_b) {
1969  return;
1970  }
1971 
1972  DiffIO *io_a = hview->io_a;
1973  DiffIO *io_b = hview->io_b;
1974  ssize_t read_a = 0, read_b = 0;
1975  st64 address_a = hview->address_a;
1976  st64 address_b = hview->address_b;
1977 
1978  do {
1979  address_a -= seek;
1980  address_b -= seek;
1981  if (address_a < 0) {
1982  address_a = 0;
1983  }
1984  if (address_b < 0) {
1985  address_b = 0;
1986  }
1987  read_a = rz_io_pread_at(io_a->io, address_a, hview->buffer_a, seek);
1988  read_b = rz_io_pread_at(io_b->io, address_b, hview->buffer_b, seek);
1989  if (read_a < 1 || read_b < 1) {
1990  break;
1991  }
1992  if (memcmp(hview->buffer_a, hview->buffer_b, seek)) {
1993  break;
1994  }
1995  if (address_a == 0 || address_b == 0) {
1996  break;
1997  }
1998  } while (1);
1999  hview->address_a = RZ_MAX(address_a, 0);
2000  hview->address_b = RZ_MAX(address_b, 0);
2001 }
2002 
2003 static void rz_diff_resize_buffer(DiffHexView *hview) {
2005 
2006  ut64 size_a = ((st64)(width / 2) * (height - 2));
2007  ut64 size_b = ((st64)(width / 2) * (height - 2));
2008  st64 video_size = width;
2009  video_size *= height;
2010 
2011  hview->line = realloc(hview->line, video_size);
2012  hview->buffer_a = realloc(hview->buffer_a, size_a);
2013  hview->buffer_b = realloc(hview->buffer_b, size_b);
2014  hview->size_a = size_a;
2015  hview->size_b = size_b;
2016  hview->screen.width = width;
2017  hview->screen.height = height;
2018 
2019  rz_cons_canvas_free(hview->canvas);
2021  hview->canvas->color = true;
2022  hview->canvas->linemode = 1;
2023 
2024  rz_diff_draw_tui(hview, false);
2025 }
2026 
2028  RzCons *console = NULL;
2029  DiffIO *io_a = NULL;
2030  DiffIO *io_b = NULL;
2031  RzConsCanvas *canvas = NULL;
2032  DiffHexView hview;
2033  bool draw_visual = true;
2034  bool show_help = false;
2035  int read, pressed;
2036  int height = ctx->screen.width;
2037  int width = ctx->screen.height;
2038  ut64 size_a = 0;
2039  ut64 size_b = 0;
2040 
2041  hview.line = NULL;
2042  hview.buffer_a = NULL;
2043  hview.buffer_b = NULL;
2044 
2045  RzCore *core = rz_core_new();
2046  if (!core) {
2047  rz_diff_error("cannot allocate core\n");
2048  goto rz_diff_hex_visual_fail;
2049  }
2050 
2051  rz_core_parse_rizinrc(core);
2052 
2053  console = rz_cons_singleton();
2054  if (!console) {
2055  rz_diff_error("cannot get console.\n");
2056  goto rz_diff_hex_visual_fail;
2057  }
2058 
2059  rz_cons_set_interactive(false);
2060 
2061  io_a = rz_diff_io_open(ctx->file_a);
2062  if (!io_a) {
2063  goto rz_diff_hex_visual_fail;
2064  }
2065 
2066  io_b = rz_diff_io_open(ctx->file_b);
2067  if (!io_b) {
2068  goto rz_diff_hex_visual_fail;
2069  }
2070 
2071  if (width < 1 && height < 1) {
2073  if (width < 1 && height < 1) {
2074  rz_diff_error("invalid screen size; use -S WxH to define the sizes.\n");
2075  goto rz_diff_hex_visual_fail;
2076  }
2077  }
2078 
2079  canvas = rz_cons_canvas_new(width, height);
2080  if (!canvas) {
2081  rz_diff_error("cannot allocate canvas. try to use -S WxH to define the sizes.\n");
2082  goto rz_diff_hex_visual_fail;
2083  }
2084 
2085  size_a = ((width / 2) * (height - 2));
2086  size_b = ((width / 2) * (height - 2));
2087 
2088  canvas->color = true;
2089  canvas->linemode = 1;
2090 
2091  st64 video_size = width;
2092  video_size *= height;
2093  hview.line = malloc(video_size);
2094  if (!hview.line) {
2095  rz_diff_error("cannot allocate line buffer.\n");
2096  goto rz_diff_hex_visual_fail;
2097  }
2098  hview.buffer_a = malloc(size_a);
2099  if (!hview.buffer_a) {
2100  rz_diff_error("cannot allocate buffer for %s.\n", io_a->filename);
2101  goto rz_diff_hex_visual_fail;
2102  }
2103  hview.buffer_b = malloc(size_b);
2104  if (!hview.buffer_b) {
2105  rz_diff_error("cannot allocate buffer for %s.\n", io_b->filename);
2106  goto rz_diff_hex_visual_fail;
2107  }
2108 
2109  hview.size_a = size_a;
2110  hview.size_b = size_b;
2111  hview.io_a = io_a;
2112  hview.io_b = io_b;
2113  hview.canvas = canvas;
2114  hview.screen.width = width;
2115  hview.screen.height = height;
2116  hview.address_a = 0;
2117  hview.address_b = 0;
2118  hview.column_descr = true;
2119  rz_diff_get_colors(&hview.colors, console->context, ctx->colors);
2120 
2121  rz_cons_show_cursor(false);
2122  rz_cons_enable_mouse(false);
2123 
2124  console->event_data = &hview;
2126 
2127  int seekmin = 0;
2128  while (draw_visual && !rz_cons_is_breaked()) {
2129  if (!rz_diff_draw_tui(&hview, show_help)) {
2130  break;
2131  }
2132  seekmin = seek_min_value(&hview);
2133  read = rz_cons_readchar();
2134  pressed = rz_cons_arrow_to_hjkl(read);
2135 
2136  if (show_help && (pressed == 'q' || pressed == 'Q')) {
2137  // allow to close the help without closing the util
2138  pressed = 0;
2139  }
2140 
2141  show_help = false;
2142  switch (pressed) {
2143  case '0':
2144  hview.column_descr = !hview.column_descr;
2145  break;
2146  case '?':
2147  show_help = true;
2148  break;
2149  case ':':
2150  prompt_offset_and_seek(&hview, seekmin);
2151  break;
2152  case '3':
2153  prompt_offset_and_seek_file(&hview, seekmin, true);
2154  break;
2155  case '4':
2156  prompt_offset_and_seek_file(&hview, seekmin, false);
2157  break;
2158  case '9':
2159  hview.address_a = hview.address_b = RZ_MIN(hview.address_a, hview.address_b);
2160  break;
2161  case 'G':
2162  case 'g':
2163  hview.address_a = io_a->filesize - seekmin;
2164  hview.address_b = io_b->filesize - seekmin;
2165  break;
2166  case 'B':
2167  case 'b':
2168  hview.address_a = 0;
2169  hview.address_b = 0;
2170  break;
2171  case 'A':
2172  case 'a':
2173  hview.address_a--;
2174  break;
2175  case 'N':
2176  case 'n':
2177  find_next_diff(&hview, seekmin);
2178  break;
2179  case 'M':
2180  case 'm':
2181  find_prev_diff(&hview, seekmin);
2182  break;
2183  case 'Z':
2184  case 'z':
2185  hview.address_a++;
2186  break;
2187  case 'D':
2188  case 'd':
2189  hview.address_b--;
2190  break;
2191  case 'C':
2192  case 'c':
2193  hview.address_b++;
2194  break;
2195  /* ARROWS */
2196  case '1':
2197  hview.address_a -= (seekmin * (height - 2));
2198  hview.address_b -= (seekmin * (height - 2));
2199  break;
2200  case '2':
2201  hview.address_a += (seekmin * (height - 2));
2202  hview.address_b += (seekmin * (height - 2));
2203  break;
2204  case 'K':
2205  case 'k':
2206  hview.address_a -= seekmin;
2207  hview.address_b -= seekmin;
2208  break;
2209  case 'J':
2210  case 'j':
2211  hview.address_a += seekmin;
2212  hview.address_b += seekmin;
2213  break;
2214  case 'L':
2215  case 'l':
2216  hview.address_a--;
2217  hview.address_b--;
2218  break;
2219  case 'H':
2220  case 'h':
2221  hview.address_a++;
2222  hview.address_b++;
2223  break;
2224  case -1: // EOF
2225  case 'Q':
2226  case 'q':
2227  draw_visual = false;
2228  default:
2229  break;
2230  }
2231  }
2232  canvas = hview.canvas;
2233  console->event_data = NULL;
2234  console->event_resize = NULL;
2235 
2236  rz_cons_show_cursor(true);
2238  rz_cons_clear();
2239  rz_cons_print(Color_RESET_TERMINAL);
2240  rz_cons_flush();
2241 
2242 rz_diff_hex_visual_fail:
2243  free(hview.line);
2244  free(hview.buffer_a);
2245  free(hview.buffer_b);
2246  rz_cons_canvas_free(canvas);
2247  rz_diff_io_close(io_a);
2248  rz_diff_io_close(io_b);
2249  rz_core_free(core);
2250  rz_cons_free();
2251  return true;
2252 }
2253 
2254 RZ_API int rz_main_rz_diff(int argc, const char **argv) {
2255  bool success = false;
2256  DiffContext ctx;
2257  rz_diff_parse_arguments(argc, argv, &ctx);
2258 
2259  switch (ctx.option) {
2260  case DIFF_OPT_DISTANCE:
2261  success = rz_diff_calculate_distance(&ctx);
2262  break;
2263  case DIFF_OPT_UNIFIED:
2264  success = rz_diff_unified_files(&ctx);
2265  break;
2266  case DIFF_OPT_GRAPH:
2267  success = rz_diff_graphs_files(&ctx);
2268  break;
2269  case DIFF_OPT_HEX_VISUAL:
2270  success = rz_diff_hex_visual(&ctx);
2271  break;
2272  case DIFF_OPT_VERSION:
2273  rz_main_version_print("rz-diff");
2274  success = true;
2275  break;
2276  case DIFF_OPT_USAGE:
2277  rz_diff_show_help(true);
2278  break;
2279  case DIFF_OPT_ERROR:
2280  break;
2281  case DIFF_OPT_HELP:
2282  success = true;
2283  // fallthrough
2284  default:
2285  rz_diff_show_help(false);
2286  break;
2287  }
2288 
2289  rz_list_free(ctx.evars);
2290  return success ? 0 : 1;
2291 }
const aarch64_field fields[]
Definition: aarch64-opc.c:205
lzma_index ** i
Definition: index.h:629
static RZ_NULLABLE RzILOpBitVector * shift(RzILOpBitVector *val, RZ_NULLABLE RzILOpBool **carry_out, arm_shifter type, RZ_OWN RzILOpBitVector *dist)
Definition: arm_il32.c:190
RZ_API RzBinPlugin * rz_bin_file_cur_plugin(RzBinFile *bf)
Definition: bfile.c:348
RZ_API RzBin * rz_bin_new(void)
Definition: bin.c:716
RZ_API RzBinFile * rz_bin_open_io(RzBin *bin, RzBinOptions *opt)
Definition: bin.c:283
RZ_API void rz_bin_options_init(RzBinOptions *opt, int fd, ut64 baseaddr, ut64 loadaddr, bool patch_relocs)
Definition: bin.c:75
RZ_API void rz_bin_free(RzBin *bin)
Definition: bin.c:440
static RzList * libs(RzBinFile *bf)
Definition: bin_coff.c:379
static RzList * classes(RzBinFile *bf)
Definition: bin_dex.c:71
static SblHeader sb
Definition: bin_mbn.c:26
RzList * entries(RzBinFile *bf)
Definition: bin_ne.c:98
RzList * symbols(RzBinFile *bf)
Definition: bin_ne.c:102
RzList * imports(RzBinFile *bf)
Definition: bin_ne.c:106
RzList * sections(RzBinFile *bf)
Definition: bin_ne.c:110
const char * desc
Definition: bin_vsf.c:19
RZ_API const RzList * rz_bin_object_get_strings(RZ_NONNULL RzBinObject *obj)
Get list of RzBinString representing the strings identified in the binary object.
Definition: bobj.c:798
struct buffer buffer
RZ_API bool rz_core_analysis_function_add(RzCore *core, const char *name, ut64 addr, bool analyze_recursively)
Definition: canalysis.c:5298
RZ_API bool rz_core_analysis_everything(RzCore *core, bool experimental, char *dh_orig)
Definition: canalysis.c:5784
RZ_API void rz_cons_canvas_print(RzConsCanvas *c)
Definition: canvas.c:423
RZ_API void rz_cons_canvas_write(RzConsCanvas *c, const char *s)
Definition: canvas.c:283
RZ_API bool rz_cons_canvas_gotoxy(RzConsCanvas *c, int x, int y)
Definition: canvas.c:184
RZ_API void rz_cons_canvas_fill(RzConsCanvas *c, int x, int y, int w, int h, char ch)
Definition: canvas.c:551
RZ_API void rz_cons_canvas_clear(RzConsCanvas *c)
Definition: canvas.c:174
RZ_API RzConsCanvas * rz_cons_canvas_new(int w, int h)
Definition: canvas.c:223
RZ_API void rz_cons_canvas_box(RzConsCanvas *c, int x, int y, int w, int h, const char *color)
Definition: canvas.c:486
RZ_API void rz_cons_canvas_free(RzConsCanvas *c)
Definition: canvas.c:150
RZ_API int rz_core_bin_update_arch_bits(RzCore *r)
Definition: cbin.c:4503
RZ_API void rz_core_parse_rizinrc(RzCore *r)
Definition: cconfig.c:3704
RZ_API RZ_BORROW RzCoreFile * rz_core_file_open(RZ_NONNULL RzCore *r, RZ_NONNULL const char *file, int flags, ut64 loadaddr)
Tries to open the file as is, otherwise tries as is a compilation of files.
Definition: cfile.c:1182
RZ_API bool rz_core_bin_load(RZ_NONNULL RzCore *r, RZ_NULLABLE const char *filenameuri, ut64 baddr)
Definition: cfile.c:942
RZ_API char * rz_core_cmd_str(RzCore *core, const char *cmd)
Executes a rizin command and returns the stdout as a string.
Definition: cmd.c:5513
static int value
Definition: cmd_api.c:93
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
RZ_API bool rz_config_eval(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *str)
Sets the configuration variable and its value passed as argument.
Definition: config.c:575
RZ_API RzConfigNode * rz_config_set(RzConfig *cfg, RZ_NONNULL const char *name, const char *value)
Definition: config.c:267
RZ_API RzConfigNode * rz_config_set_i(RzConfig *cfg, RZ_NONNULL const char *name, const ut64 i)
Definition: config.c:419
RZ_API RzConfigNode * rz_config_set_b(RzConfig *cfg, RZ_NONNULL const char *name, bool value)
Definition: config.c:201
RZ_API int rz_cons_get_size(int *rows)
Definition: cons.c:1446
RZ_API bool rz_cons_enable_mouse(const bool enable)
Definition: cons.c:500
RZ_API RzCons * rz_cons_singleton(void)
Definition: cons.c:300
RZ_API void rz_cons_clear_line(int std_err)
Definition: cons.c:756
RZ_API void rz_cons_set_interactive(bool x)
Definition: cons.c:1724
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
RZ_API void rz_cons_goto_origin_reset(void)
Definition: cons.c:732
RZ_API void rz_cons_show_cursor(int cursor)
Definition: cons.c:1581
RZ_API void rz_cons_flush(void)
Definition: cons.c:959
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
RZ_API void rz_cons_gotoxy(int x, int y)
Definition: cons.c:724
RZ_API void rz_cons_clear(void)
Definition: cons.c:787
RZ_API RzCons * rz_cons_free(void)
Definition: cons.c:658
#define RZ_API
#define NULL
Definition: cris-opc.c:27
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
struct config_s config
uint32_t ut32
RZ_API RZ_OWN RzDiff * rz_diff_generic_new(RZ_BORROW const void *a, ut32 a_size, RZ_BORROW const void *b, ut32 b_size, RZ_NONNULL RzDiffMethods *methods)
Returns the structure needed to diff arrays of user defined types.
Definition: diff.c:259
RZ_API ut32 rz_diff_hash_data(RZ_NULLABLE const ut8 *buffer, ut32 size)
Calculates the hash of any given data.
Definition: diff.c:103
RZ_API RZ_OWN RzDiff * rz_diff_lines_new(RZ_BORROW const char *a, RZ_BORROW const char *b, RZ_NULLABLE RzDiffIgnoreLine ignore)
Returns the structure needed to diff lines.
Definition: diff.c:219
RZ_API RZ_OWN RzDiff * rz_diff_bytes_new(RZ_BORROW const ut8 *a, ut32 a_size, RZ_BORROW const ut8 *b, ut32 b_size, RZ_NULLABLE RzDiffIgnoreByte ignore)
Returns the structure needed to diff buffers of ut8.
Definition: diff.c:188
RZ_API void rz_diff_free(RZ_NULLABLE RzDiff *diff)
frees the diff structure
Definition: diff.c:295
RZ_API bool rz_diff_myers_distance(RZ_NONNULL const ut8 *a, ut32 la, RZ_NONNULL const ut8 *b, ut32 lb, RZ_NULLABLE ut32 *distance, RZ_NULLABLE double *similarity)
Calculates the distance between two buffers using the Myers algorithm.
Definition: distance.c:14
RZ_API bool rz_diff_levenstein_distance(RZ_NONNULL const ut8 *a, ut32 la, RZ_NONNULL const ut8 *b, ut32 lb, RZ_NULLABLE ut32 *distance, RZ_NULLABLE double *similarity)
Calculates the distance between two buffers using the Levenshtein algorithm.
Definition: distance.c:68
RZ_API RzFlagItem * rz_flag_get(RzFlag *f, const char *name)
Definition: flag.c:310
RZ_API bool rz_core_gdiff_function_2_files(RzCore *c, RzCore *c2, ut64 addr, ut64 addr2)
Calculates basic block differences of 2 functions within 2 files.
Definition: gdiff.c:47
RZ_API bool rz_core_diff_show_function(RzCore *core, RzCore *core2, ut64 addr1, bool json)
Generate a json or dot output of the graph and its data.
Definition: gdiff.c:574
RZ_API void rz_core_diff_show(RzCore *c, RzCore *c2, bool json)
Definition: gdiff.c:161
RZ_API bool rz_core_gdiff_2_files(RzCore *c, RzCore *c2)
Calculates basic block differences of all functions within 2 files.
Definition: gdiff.c:89
unsigned char match[65280+2]
Definition: gun.c:165
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API int rz_cons_arrow_to_hjkl(int ch)
Definition: input.c:78
RZ_API int rz_cons_fgets(char *buf, int len, int argc, const char **argv)
Definition: input.c:339
RZ_API int rz_cons_readchar(void)
Definition: input.c:619
voidpf void uLong size
Definition: ioapi.h:138
const char * filename
Definition: ioapi.h:137
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
static int compare(const char *s1, const char *s2, int l1, int l2)
Definition: chmd.c:864
RZ_API void rz_core_free(RzCore *c)
Definition: core.c:2683
RZ_API RzCore * rz_core_new(void)
Definition: core.c:866
static void rz_diff_get_colors(DiffColors *dcolors, RzConsContext *ctx, bool colors)
Definition: rz-diff.c:396
static int import_compare(const RzBinImport *a, const RzBinImport *b)
Definition: rz-diff.c:690
static void rz_diff_show_help(bool usage_only)
Definition: rz-diff.c:195
static RzDiff * rz_diff_symbols_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr)
Definition: rz-diff.c:771
static ut32 libs_hash(const char *elem)
Definition: rz-diff.c:1023
static const void * rz_diff_list_elem_at(const RzList *array, ut32 index)
Definition: rz-diff.c:672
#define rz_diff_error_opt(x, o, f,...)
Definition: rz-diff.c:141
static int seek_min_value(DiffHexView *hview)
Definition: rz-diff.c:1612
static ut32 string_hash_addr(const RzBinString *elem)
Definition: rz-diff.c:801
static void prompt_offset_and_seek(DiffHexView *hview, ut64 minseek)
Definition: rz-diff.c:1854
static ut32 field_hash_addr(const RzBinField *elem)
Definition: rz-diff.c:1182
static char * execute_command(const char *command, const char *filename, DiffContext *ctx)
Definition: rz-diff.c:1259
#define P(x)
static bool rz_diff_calculate_distance(DiffContext *ctx)
Definition: rz-diff.c:486
static DiffIO * rz_diff_io_open(const char *file)
Definition: rz-diff.c:404
DiffOption
Definition: rz-diff.c:52
@ DIFF_OPT_HELP
Definition: rz-diff.c:55
@ DIFF_OPT_DISTANCE
Definition: rz-diff.c:58
@ DIFF_OPT_GRAPH
Definition: rz-diff.c:60
@ DIFF_OPT_UNIFIED
Definition: rz-diff.c:59
@ DIFF_OPT_UNKNOWN
Definition: rz-diff.c:53
@ DIFF_OPT_ERROR
Definition: rz-diff.c:54
@ DIFF_OPT_VERSION
Definition: rz-diff.c:57
@ DIFF_OPT_HEX_VISUAL
Definition: rz-diff.c:61
@ DIFF_OPT_USAGE
Definition: rz-diff.c:56
static RzDiff * rz_diff_libraries_new(DiffFile *dfile_a, DiffFile *dfile_b)
Definition: rz-diff.c:1037
struct diff_screen_t DiffScreen
static ut32 symbol_hash_addr(const RzBinSymbol *elem)
Definition: rz-diff.c:728
static bool rz_diff_hex_visual(DiffContext *ctx)
Definition: rz-diff.c:2027
#define rz_diff_ctx_set_dist(x, t)
Definition: rz-diff.c:190
#define rz_diff_error_ret(fail, f,...)
Definition: rz-diff.c:137
static RzDiff * rz_diff_entries_new(DiffFile *dfile_a, DiffFile *dfile_b)
Definition: rz-diff.c:993
static int string_compare_addr(const RzBinString *a, const RzBinString *b)
Definition: rz-diff.c:810
static int diff_hexdump_partial(DiffHexView *hview, int hexlen, int lp, int lsize, const ut8 *bytes_a, const ut8 *bytes_b, ut64 address_a, ut64 address_b, ut64 size_a, ut64 size_b, ut64 pos, ssize_t read_a, ssize_t read_b, ssize_t skip_a, ssize_t skip_b)
Definition: rz-diff.c:1500
static RzCoreFile * rz_diff_load_file_with_core(const char *filename, const char *architecture, ut32 arch_bits, RzList *evars, bool colors)
Definition: rz-diff.c:554
static bool rz_diff_file_open(DiffFile *dfile, const char *filename)
Definition: rz-diff.c:617
struct diff_io_t DiffIO
static void symbol_stringify_addr(const RzBinSymbol *elem, RzStrBuf *sb)
Definition: rz-diff.c:753
RZ_API int rz_main_rz_diff(int argc, const char **argv)
Definition: rz-diff.c:2254
static ut32 section_hash(const RzBinSection *elem)
Definition: rz-diff.c:1122
static int field_compare_addr(const RzBinField *a, const RzBinField *b)
Definition: rz-diff.c:1192
static void libs_stringify(const char *elem, RzStrBuf *sb)
Definition: rz-diff.c:1033
#define rz_diff_ctx_set_def(x, k, d, v)
Definition: rz-diff.c:157
#define rz_diff_set_def(x, d, v)
Definition: rz-diff.c:148
static int symbol_compare_addr(const RzBinSymbol *a, const RzBinSymbol *b)
Definition: rz-diff.c:740
static ut32 class_hash_addr(const RzBinClass *elem)
Definition: rz-diff.c:876
static int len_draw_hexdump(DiffHexView *hview)
Definition: rz-diff.c:1592
#define rz_diff_ctx_set_mode(x, m)
Definition: rz-diff.c:192
static RzDiff * rz_diff_sections_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr)
Definition: rz-diff.c:1152
DiffType
Definition: rz-diff.c:35
@ DIFF_TYPE_LINES
Definition: rz-diff.c:45
@ DIFF_TYPE_LIBRARIES
Definition: rz-diff.c:44
@ DIFF_TYPE_FIELDS
Definition: rz-diff.c:41
@ DIFF_TYPE_BYTES
Definition: rz-diff.c:37
@ DIFF_TYPE_FUNCTIONS
Definition: rz-diff.c:42
@ DIFF_TYPE_SECTIONS
Definition: rz-diff.c:46
@ DIFF_TYPE_IMPORTS
Definition: rz-diff.c:43
@ DIFF_TYPE_ENTRIES
Definition: rz-diff.c:40
@ DIFF_TYPE_STRINGS
Definition: rz-diff.c:47
@ DIFF_TYPE_PLOTDIFF
Definition: rz-diff.c:49
@ DIFF_TYPE_COMMAND
Definition: rz-diff.c:39
@ DIFF_TYPE_SYMBOLS
Definition: rz-diff.c:48
@ DIFF_TYPE_CLASSES
Definition: rz-diff.c:38
@ DIFF_TYPE_UNKNOWN
Definition: rz-diff.c:36
static void import_stringify(const RzBinImport *elem, RzStrBuf *sb)
Definition: rz-diff.c:685
static char * visual_prompt(DiffHexView *hview, const char *prompt)
Definition: rz-diff.c:1840
struct diff_function_t DiffFunction
#define SAFE_STR_DEF(x, y)
Definition: rz-diff.c:12
static ut32 field_hash(const RzBinField *elem)
Definition: rz-diff.c:1212
static bool rz_diff_graphs_files(DiffContext *ctx)
Definition: rz-diff.c:1413
static RzDiff * rz_diff_command_new(DiffContext *ctx)
Definition: rz-diff.c:1274
static int symbol_compare(const RzBinSymbol *a, const RzBinSymbol *b)
Definition: rz-diff.c:761
static int libs_compare(const char *a, const char *b)
Definition: rz-diff.c:1027
static ut32 string_hash(const RzBinString *elem)
Definition: rz-diff.c:828
static void entry_stringify(const RzBinAddr *elem, RzStrBuf *sb)
Definition: rz-diff.c:965
enum diff_hex_len_t DiffHexLen
struct diff_context_t DiffContext
DiffDistance
Definition: rz-diff.c:29
@ DIFF_DISTANCE_MYERS
Definition: rz-diff.c:31
@ DIFF_DISTANCE_UNKNOWN
Definition: rz-diff.c:30
@ DIFF_DISTANCE_LEVENSHTEIN
Definition: rz-diff.c:32
static ut32 entry_hash(const RzBinAddr *elem)
Definition: rz-diff.c:942
static void rz_diff_file_close(DiffFile *file)
Definition: rz-diff.c:662
static void rz_diff_parse_arguments(int argc, const char **argv, DiffContext *ctx)
Definition: rz-diff.c:254
static RzDiff * rz_diff_fields_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr)
Definition: rz-diff.c:1229
static RzDiff * rz_diff_imports_new(DiffFile *dfile_a, DiffFile *dfile_b)
Definition: rz-diff.c:698
static int section_compare(const RzBinSection *a, const RzBinSection *b)
Definition: rz-diff.c:1130
static int class_compare(const RzBinClass *a, const RzBinClass *b)
Definition: rz-diff.c:901
#define rz_diff_error(f,...)
Definition: rz-diff.c:134
DiffMode
Definition: rz-diff.c:23
@ DIFF_MODE_QUIET
Definition: rz-diff.c:26
@ DIFF_MODE_STANDARD
Definition: rz-diff.c:24
@ DIFF_MODE_JSON
Definition: rz-diff.c:25
struct diff_colors_t DiffColors
static void section_stringify(const RzBinSection *elem, RzStrBuf *sb)
Definition: rz-diff.c:1140
static void class_stringify(const RzBinClass *elem, RzStrBuf *sb)
Definition: rz-diff.c:908
static int seek_min_shift(DiffHexView *hview)
Definition: rz-diff.c:1602
static void rz_diff_io_close(DiffIO *dio)
Definition: rz-diff.c:439
static int entry_compare(const RzBinAddr *a, const RzBinAddr *b)
Definition: rz-diff.c:952
static bool rz_diff_draw_tui(DiffHexView *hview, bool show_help)
Definition: rz-diff.c:1632
static int field_compare(const RzBinField *a, const RzBinField *b)
Definition: rz-diff.c:1218
#define IF_STRCMP_S(ret, x, y)
Definition: rz-diff.c:14
static int class_compare_addr(const RzBinClass *a, const RzBinClass *b)
Definition: rz-diff.c:884
#define MEGABYTE(x)
Definition: rz-diff.c:11
static int section_compare_addr(const RzBinSection *a, const RzBinSection *b)
Definition: rz-diff.c:1083
static int offset_len(DiffHexView *hview)
Definition: rz-diff.c:1622
struct diff_hex_view_t DiffHexView
static ut32 section_hash_addr(const RzBinSection *elem)
Definition: rz-diff.c:1067
static ut32 class_hash(const RzBinClass *elem)
Definition: rz-diff.c:895
#define SAFE_STR(x)
Definition: rz-diff.c:13
static void find_prev_diff(DiffHexView *hview, ut64 seek)
Definition: rz-diff.c:1967
static bool rz_diff_unified_files(DiffContext *ctx)
Definition: rz-diff.c:1297
static int string_compare(const RzBinString *a, const RzBinString *b)
Definition: rz-diff.c:832
static void class_stringify_addr(const RzBinClass *elem, RzStrBuf *sb)
Definition: rz-diff.c:891
#define rz_diff_file_get(df, n)
Definition: rz-diff.c:668
static ut32 symbol_hash(const RzBinSymbol *elem)
Definition: rz-diff.c:757
static bool convert_offset_from_input(RzCore *core, const char *input, ut64 *offset)
Definition: rz-diff.c:1398
static void diff_hexdump_line(DiffHexView *hview, DiffHexLen hlen, ut64 pos, ssize_t read_a, ssize_t read_b, ssize_t skip_a, ssize_t skip_b)
Definition: rz-diff.c:1560
static RzBinFile * core_get_file(RzCoreFile *cfile)
Definition: rz-diff.c:550
static void section_stringify_addr(const RzBinSection *elem, RzStrBuf *sb)
Definition: rz-diff.c:1109
#define rz_diff_ctx_add_evar(x, o)
Definition: rz-diff.c:181
static void string_stringify_addr(const RzBinString *elem, RzStrBuf *sb)
Definition: rz-diff.c:824
static void field_stringify(const RzBinField *elem, RzStrBuf *sb)
Definition: rz-diff.c:1225
static RzDiff * rz_diff_strings_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr)
Definition: rz-diff.c:846
static void prompt_offset_and_seek_file(DiffHexView *hview, ut64 minseek, bool is_file0)
Definition: rz-diff.c:1877
static void rz_diff_resize_buffer(DiffHexView *hview)
Definition: rz-diff.c:2003
#define rz_diff_ctx_set_opt(x, o)
Definition: rz-diff.c:193
#define rz_diff_ctx_set_unsigned(x, k, i)
Definition: rz-diff.c:173
static bool rz_diff_is_file(const char *file)
Definition: rz-diff.c:244
static RzDiff * rz_diff_classes_new(DiffFile *dfile_a, DiffFile *dfile_b, bool compare_addr)
Definition: rz-diff.c:912
static void find_next_diff(DiffHexView *hview, ut64 seek)
Definition: rz-diff.c:1909
static void string_stringify(const RzBinString *elem, RzStrBuf *sb)
Definition: rz-diff.c:842
static void symbol_stringify(const RzBinSymbol *elem, RzStrBuf *sb)
Definition: rz-diff.c:767
static void field_stringify_addr(const RzBinField *elem, RzStrBuf *sb)
Definition: rz-diff.c:1207
diff_hex_len_t
Definition: rz-diff.c:1494
@ DIFF_HEX_8
Definition: rz-diff.c:1495
@ DIFF_HEX_16
Definition: rz-diff.c:1496
@ DIFF_HEX_32
Definition: rz-diff.c:1497
#define rz_diff_ctx_set_type(x, t)
Definition: rz-diff.c:191
static ut32 import_hash(const RzBinImport *elem)
Definition: rz-diff.c:678
static ut8 * rz_diff_slurp_file(const char *file, size_t *size)
Definition: rz-diff.c:449
struct diff_file_t DiffFile
#define printline(fmt,...)
static int show_help(const char *argv0, int line)
Definition: rz-find.c:173
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 void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
RZ_API RZ_BORROW void * rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n)
Returns the N-th element of the list.
Definition: list.c:574
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
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 rz_core_loadlibs(RzCore *core, int where)
Definition: libs.c:119
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
RZ_API void rz_line_set_prompt(const char *prompt)
Definition: line.c:56
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
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")
int type
Definition: mipsasm.c:17
line
Definition: setup.py:34
struct @219 colors[]
#define RZ_BIN_ENTRY_TYPE_PREINIT
Definition: rz_bin.h:38
#define RZ_BIN_ENTRY_TYPE_TLS
Definition: rz_bin.h:37
#define RZ_BIN_ENTRY_TYPE_FINI
Definition: rz_bin.h:36
#define RZ_BIN_ENTRY_TYPE_INIT
Definition: rz_bin.h:35
#define RZ_BIN_ENTRY_TYPE_PROGRAM
Definition: rz_bin.h:33
#define RZ_BIN_TYPE_UNKNOWN_STR
Definition: rz_bin.h:134
#define RZ_BIN_BIND_UNKNOWN_STR
Definition: rz_bin.h:115
#define RZ_BIN_ENTRY_TYPE_MAIN
Definition: rz_bin.h:34
#define Color_RESET
Definition: rz_cons.h:617
void(* RzConsEvent)(void *)
Definition: rz_cons.h:346
#define RUNE_ARROW_RIGHT
Definition: rz_cons.h:409
#define RUNE_ARROW_DOWN
Definition: rz_cons.h:412
#define RUNE_ARROW_UP
Definition: rz_cons.h:411
#define RUNE_ARROW_LEFT
Definition: rz_cons.h:410
#define Color_RESET_TERMINAL
Definition: rz_cons.h:615
#define Color_INVERT
Definition: rz_cons.h:606
const void *(* RzDiffMethodElemAt)(RZ_BORROW const void *array, ut32 index)
Definition: rz_diff.h:36
ut32(* RzDiffMethodElemHash)(RZ_BORROW const void *elem)
Definition: rz_diff.h:37
void(* RzDiffMethodStringify)(RZ_BORROW const void *elem, RZ_BORROW RzStrBuf *sb)
Definition: rz_diff.h:40
int(* RzDiffMethodCompare)(RZ_BORROW const void *a_elem, RZ_BORROW const void *b_elem)
Definition: rz_diff.h:38
RZ_API bool rz_file_is_directory(const char *str)
Definition: file.c:167
RZ_API void rz_getopt_init(RzGetopt *go, int argc, const char **argv, const char *ostr)
Definition: getopt.c:17
RZ_API int rz_getopt_next(RzGetopt *opt)
Definition: getopt.c:29
RZ_API ut64 rz_io_desc_size(RzIODesc *desc)
Definition: io_desc.c:224
RZ_API void rz_io_free(RzIO *io)
Definition: io.c:126
RZ_API void rz_io_bind(RzIO *io, RzIOBind *bnd)
Definition: io.c:550
RZ_API RzIODesc * rz_io_open_nomap(RzIO *io, const char *uri, int flags, int mode)
Definition: io.c:145
RZ_API int rz_io_pread_at(RzIO *io, ut64 paddr, ut8 *buf, int len)
Definition: io.c:269
RZ_API RzIO * rz_io_new(void)
Definition: io.c:110
RZ_API bool rz_io_desc_close(RzIODesc *desc)
Definition: io_desc.c:165
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
RZ_API int rz_main_version_print(const char *program)
Definition: main.c:49
RZ_API int rz_num_is_valid_input(RzNum *num, const char *input_value)
Definition: unum.c:676
RZ_API ut64 rz_num_get_input_value(RzNum *num, const char *input_value)
Definition: unum.c:681
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API const char * pj_string(PJ *pj)
Definition: pj.c:57
RZ_API void pj_free(PJ *j)
Definition: pj.c:34
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API PJ * pj_kn(PJ *j, const char *k, ut64 n)
Definition: pj.c:121
RZ_API PJ * pj_kd(PJ *j, const char *k, double d)
Definition: pj.c:136
RZ_API const char * rz_str_trim_head_ro(const char *str)
Definition: str_trim.c:86
#define IS_DIGIT(x)
Definition: rz_str_util.h:11
#define IS_NULLSTR(x)
Definition: rz_str_util.h:4
RZ_API const char * rz_strbuf_setf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API int rz_sys_usleep(int usecs)
Sleep for usecs microseconds.
Definition: sys.c:317
#define RZ_SYS_DIR
Definition: rz_types.h:218
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_W
Definition: rz_types.h:94
#define RZ_PERM_X
Definition: rz_types.h:95
#define RZ_PERM_SHAR
Definition: rz_types.h:100
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10
#define UT32_MAX
Definition: rz_types_base.h:99
#define RZ_MAX(x, y)
#define UT64_MAX
Definition: rz_types_base.h:86
#define UT16_MAX
static void * rz_pvector_at(const RzPVector *vec, size_t index)
Definition: rz_vector.h:236
static int
Definition: sfsocketcall.h:114
int ssize_t
Definition: sftypes.h:39
#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: malloc.c:26
Definition: buffer.h:15
const char * reset
Definition: rz-diff.c:115
const char * number
Definition: rz-diff.c:111
const char * legenda
Definition: rz-diff.c:114
const char * match
Definition: rz-diff.c:112
const char * unmatch
Definition: rz-diff.c:113
const char * file_b
Definition: rz-diff.c:83
bool analyze_all
Definition: rz-diff.c:78
const char * file_a
Definition: rz-diff.c:82
bool compare_addresses
Definition: rz-diff.c:75
DiffMode mode
Definition: rz-diff.c:71
bool show_time
Definition: rz-diff.c:76
DiffType type
Definition: rz-diff.c:70
const char * architecture
Definition: rz-diff.c:79
DiffOption option
Definition: rz-diff.c:72
const char * input_b
Definition: rz-diff.c:81
const char * input_a
Definition: rz-diff.c:80
DiffDistance distance
Definition: rz-diff.c:73
bool colors
Definition: rz-diff.c:77
RzList * evars
Definition: rz-diff.c:85
DiffScreen screen
Definition: rz-diff.c:84
ut32 arch_bits
Definition: rz-diff.c:74
RzBinPlugin * plugin
Definition: rz-diff.c:97
RzBin * bin
Definition: rz-diff.c:99
DiffIO * dio
Definition: rz-diff.c:100
RzBinFile * file
Definition: rz-diff.c:96
char * name
Definition: rz-diff.c:104
int n_instructions
Definition: rz-diff.c:107
DiffScreen screen
Definition: rz-diff.c:131
char * line
Definition: rz-diff.c:119
ut8 * buffer_b
Definition: rz-diff.c:121
DiffIO * io_a
Definition: rz-diff.c:126
RzConsCanvas * canvas
Definition: rz-diff.c:130
DiffColors colors
Definition: rz-diff.c:129
ut64 address_b
Definition: rz-diff.c:125
bool column_descr
Definition: rz-diff.c:128
DiffIO * io_b
Definition: rz-diff.c:127
ut64 address_a
Definition: rz-diff.c:124
ut8 * buffer_a
Definition: rz-diff.c:120
const char * filename
Definition: rz-diff.c:89
RzIO * io
Definition: rz-diff.c:91
ut64 filesize
Definition: rz-diff.c:90
int height
Definition: rz-diff.c:66
Definition: gzappend.c:170
Definition: engine.c:71
Definition: z80asm.h:102
Definition: rz_pj.h:12
ut64 vaddr
Definition: rz_bin.h:186
ut64 paddr
Definition: rz_bin.h:187
char * super
Definition: rz_bin.h:649
char * name
Definition: rz_bin.h:647
ut64 vaddr
Definition: rz_bin.h:762
char * name
Definition: rz_bin.h:767
char * type
Definition: rz_bin.h:768
ut64 paddr
Definition: rz_bin.h:763
XX curplugin == o->plugin.
Definition: rz_bin.h:298
RzBinObject * o
Definition: rz_bin.h:305
const char * type
Definition: rz_bin.h:704
const char * bind
Definition: rz_bin.h:703
char * name
Definition: rz_bin.h:701
RzList * maps
Definition: rz_bin.h:266
char * name
Definition: rz_bin.h:619
char * string
Definition: rz_bin.h:752
char * name
Definition: rz_bin.h:675
char * classname
Definition: rz_bin.h:678
char * dname
Definition: rz_bin.h:676
char * libname
Definition: rz_bin.h:677
RzConsEvent event_resize
Definition: rz_cons.h:522
void * event_data
Definition: rz_cons.h:523
bool use_utf8
Definition: rz_cons.h:559
RzConsContext * context
Definition: rz_cons.h:502
RzFlag * flags
Definition: rz_core.h:330
RzPrint * print
Definition: rz_core.h:327
RzConfig * config
Definition: rz_core.h:300
RzDiffMethodElemAt elem_at
can be either be an element of A or B
Definition: rz_diff.h:42
Definition: diff.c:89
ut64 offset
Definition: rz_flag.h:38
const char * arg
Definition: rz_getopt.h:15
int fd
Definition: rz_io.h:96
Definition: rz_io.h:59
struct rz_io_desc_t * desc
Definition: rz_io.h:60
bool scr_prompt
Definition: rz_print.h:121
const char * command
Definition: main.c:7
int pos
Definition: main.c:11
int width
Definition: main.c:10
int height
Definition: main.c:10
RZ_API RZ_OWN char * rz_diff_unified_text(RZ_NONNULL RzDiff *diff, RZ_NULLABLE const char *from, RZ_NULLABLE const char *to, bool show_time, bool color)
Produces a diff output with A and B inputs presented immediately adjacent to each other.
Definition: unified_diff.c:333
RZ_API RZ_OWN PJ * rz_diff_unified_json(RZ_NONNULL RzDiff *diff, RZ_NULLABLE const char *from, RZ_NULLABLE const char *to, bool show_time)
Produces a diff output to convert A in B in a JSON format.
Definition: unified_diff.c:409
static int color
Definition: visual.c:20
static char * prompt(const char *str, const char *txt)
Definition: vmenus.c:30
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int file
Definition: z80asm.c:58
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)
diff_output_t output
Definition: zipcmp.c:237
static int seek(char *argv[])
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115