Rizin
unix-like reverse engineering framework and cli tools
gdiff.c File Reference
#include <stdio.h>
#include <string.h>
#include <rz_analysis.h>
#include <rz_list.h>
#include <rz_util.h>
#include <rz_core.h>

Go to the source code of this file.

Functions

RZ_API bool rz_core_gdiff_function_1_file (RzCore *c, ut64 addr, ut64 addr2)
 Calculates basic block differences of 2 functions within the same file. More...
 
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. More...
 
RZ_API bool rz_core_gdiff_2_files (RzCore *c, RzCore *c2)
 Calculates basic block differences of all functions within 2 files. More...
 
static void diffrow (ut64 addr, const char *name, ut32 size, int maxnamelen, int digits, ut64 addr2, const char *name2, ut32 size2, double dist, bool bare, bool color)
 
RZ_API void rz_core_diff_show (RzCore *c, RzCore *c2, bool json)
 
static const char * diff_color (RzAnalysisBlock *bbi)
 
static void print_color_node (RzCore *core, RzAnalysisBlock *bbi)
 
static int graph_construct_nodes (RzCore *core, RzCore *core2, RzAnalysisFunction *fcn, PJ *pj)
 
static int graph_construct_edges (RzCore *core, RzAnalysisFunction *fcn)
 
static int draw_graph_nodes (RzCore *core, RzCore *core2, RzAnalysisFunction *fcn, PJ *pj)
 
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. More...
 

Function Documentation

◆ diff_color()

static const char* diff_color ( RzAnalysisBlock bbi)
static

Definition at line 334 of file gdiff.c.

334  {
335  if (!bbi->diff) {
336  return "white";
337  }
338 
339  switch (bbi->diff->type) {
341  return "lightgray";
343  return bbi->diff->dist >= 0.5 ? "yellow" : "red";
344  default:
345  return "turquoise";
346  }
347 }
@ RZ_ANALYSIS_DIFF_TYPE_MATCH
Definition: rz_analysis.h:206
@ RZ_ANALYSIS_DIFF_TYPE_UNMATCH
Definition: rz_analysis.h:207
RzAnalysisDiff * diff
Definition: rz_analysis.h:872

References rz_analysis_bb_t::diff, rz_analysis_diff_t::dist, RZ_ANALYSIS_DIFF_TYPE_MATCH, RZ_ANALYSIS_DIFF_TYPE_UNMATCH, and rz_analysis_diff_t::type.

Referenced by graph_construct_nodes().

◆ diffrow()

static void diffrow ( ut64  addr,
const char *  name,
ut32  size,
int  maxnamelen,
int  digits,
ut64  addr2,
const char *  name2,
ut32  size2,
double  dist,
bool  bare,
bool  color 
)
static

Definition at line 124 of file gdiff.c.

126  {
127 
128  const char *type = NULL;
129  const char *prefix = NULL;
130  const char *suffix = color ? Color_RESET : "";
131 
132  if (dist == 1.0) {
133  prefix = color ? Color_BGREEN : "";
134  type = color ? Color_BGREEN "MATCH " Color_RESET : "MATCH ";
135  } else if (dist >= RZ_ANALYSIS_DIFF_THRESHOLD) {
136  prefix = color ? Color_BYELLOW : "";
137  type = color ? Color_BYELLOW "SIMILAR" Color_RESET : "SIMILAR";
138  } else {
139  prefix = color ? Color_BRED : "";
140  type = color ? Color_BRED "UNMATCH" Color_RESET : "UNMATCH";
141  }
142 
143  if (bare) {
144  if (addr2 == UT64_MAX || !name2) {
145  printf("0x%016" PFMT64x " | %7s (%s%f%s)\n", addr, type, prefix, dist, suffix);
146  } else {
147  printf("0x%016" PFMT64x " | %7s (%s%f%s) | 0x%016" PFMT64x "\n", addr, type, prefix, dist, suffix, addr2);
148  }
149  } else {
150  if (addr2 == UT64_MAX || !name2) {
151  printf("%*s %*d 0x%016" PFMT64x " | %7s (%s%f%s)\n",
152  maxnamelen, name, digits, size, addr, type, prefix, dist, suffix);
153  } else {
154  printf("%*s %*d 0x%016" PFMT64x " | %7s (%s%f%s) | 0x%016" PFMT64x " %*d %s\n",
155  maxnamelen, name, digits, size, addr, type, prefix, dist, suffix, addr2,
156  digits, size2, name2);
157  }
158  }
159 }
#define NULL
Definition: cris-opc.c:27
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
unsigned char suffix[65536]
Definition: gun.c:164
unsigned short prefix[65536]
Definition: gun.c:163
voidpf void uLong size
Definition: ioapi.h:138
int type
Definition: mipsasm.c:17
#define RZ_ANALYSIS_DIFF_THRESHOLD
Definition: rz_analysis.h:202
#define Color_BYELLOW
Definition: rz_cons.h:650
#define Color_RESET
Definition: rz_cons.h:617
#define Color_BRED
Definition: rz_cons.h:642
#define Color_BGREEN
Definition: rz_cons.h:646
#define PFMT64x
Definition: rz_types.h:393
#define UT64_MAX
Definition: rz_types_base.h:86
Definition: z80asm.h:102
static int color
Definition: visual.c:20
static int addr
Definition: z80asm.c:58

References addr, color, Color_BGREEN, Color_BRED, Color_BYELLOW, Color_RESET, NULL, PFMT64x, prefix, printf(), RZ_ANALYSIS_DIFF_THRESHOLD, suffix, type, and UT64_MAX.

Referenced by rz_core_diff_show().

◆ draw_graph_nodes()

static int draw_graph_nodes ( RzCore core,
RzCore core2,
RzAnalysisFunction fcn,
PJ pj 
)
static

Definition at line 532 of file gdiff.c.

532  {
533  rz_return_val_if_fail(fcn && fcn->bbs, -1);
534  int nodes = 0;
535 
536  if (pj) {
537  char *fcn_name_escaped = rz_str_escape_utf8_for_json(fcn->name, -1);
538  pj_o(pj);
539  pj_ks(pj, "name", rz_str_get_null(fcn_name_escaped));
540  free(fcn_name_escaped);
541  pj_kn(pj, "offset", fcn->addr);
542  pj_ki(pj, "ninstr", fcn->ninstr);
543  pj_ki(pj, "nargs",
544  rz_analysis_var_count(core->analysis, fcn, 'r', 1) +
545  rz_analysis_var_count(core->analysis, fcn, 's', 1) +
546  rz_analysis_var_count(core->analysis, fcn, 'b', 1));
547  pj_ki(pj, "nlocals",
548  rz_analysis_var_count(core->analysis, fcn, 'r', 0) +
549  rz_analysis_var_count(core->analysis, fcn, 's', 0) +
550  rz_analysis_var_count(core->analysis, fcn, 'b', 0));
551  pj_kn(pj, "size", rz_analysis_function_linear_size(fcn));
552  pj_ki(pj, "stack", fcn->maxstack);
553  pj_ks(pj, "type", rz_analysis_fcntype_tostring(fcn->type));
554  pj_k(pj, "blocks");
555  pj_a(pj);
556  }
557  nodes += graph_construct_nodes(core, core2, fcn, pj);
558  if (!pj) {
559  nodes += graph_construct_edges(core, fcn);
560  }
561  if (pj) {
562  pj_end(pj);
563  pj_end(pj);
564  }
565  return nodes;
566 }
RZ_API ut64 rz_analysis_function_linear_size(RzAnalysisFunction *fcn)
Definition: function.c:318
RZ_API const char * rz_analysis_fcntype_tostring(int type)
Definition: fcn.c:35
static int graph_construct_nodes(RzCore *core, RzCore *core2, RzAnalysisFunction *fcn, PJ *pj)
Definition: gdiff.c:358
static int graph_construct_edges(RzCore *core, RzAnalysisFunction *fcn)
Definition: gdiff.c:491
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API PJ * pj_ki(PJ *j, const char *k, int d)
Definition: pj.c:149
RZ_API PJ * pj_k(PJ *j, const char *k)
Definition: pj.c:104
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
Definition: pj.c:170
RZ_API PJ * pj_kn(PJ *j, const char *k, ut64 n)
Definition: pj.c:121
RZ_API PJ * pj_a(PJ *j)
Definition: pj.c:81
static const char * rz_str_get_null(const char *str)
Definition: rz_str.h:190
RZ_API char * rz_str_escape_utf8_for_json(const char *s, int len)
Definition: str.c:1834
RzAnalysis * analysis
Definition: rz_core.h:322
RZ_API int rz_analysis_var_count(RzAnalysis *a, RzAnalysisFunction *fcn, int kind, int type)
Definition: var.c:574

References rz_analysis_function_t::addr, rz_core_t::analysis, rz_analysis_function_t::bbs, free(), graph_construct_edges(), graph_construct_nodes(), rz_analysis_function_t::maxstack, rz_analysis_function_t::name, rz_analysis_function_t::ninstr, pj_a(), pj_end(), pj_k(), pj_ki(), pj_kn(), pj_ks(), pj_o(), rz_analysis_fcntype_tostring(), rz_analysis_function_linear_size(), rz_analysis_var_count(), rz_return_val_if_fail, rz_str_escape_utf8_for_json(), rz_str_get_null(), and rz_analysis_function_t::type.

Referenced by rz_core_diff_show_function().

◆ graph_construct_edges()

static int graph_construct_edges ( RzCore core,
RzAnalysisFunction fcn 
)
static

Definition at line 491 of file gdiff.c.

491  {
492  RzAnalysisBlock *bbi;
493  RzListIter *iter;
494  const char *pal_jump = "#0037da";
495  const char *pal_fail = "#c50f1f";
496  const char *pal_true = "#13a10e";
497  int nodes = 0;
498  rz_list_foreach (fcn->bbs, iter, bbi) {
499  if (bbi->jump != UT64_MAX) {
500  nodes++;
501  printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color=\"%s\"];\n",
502  bbi->addr, bbi->jump,
503  bbi->fail != UT64_MAX ? pal_true : pal_jump);
504  print_color_node(core, bbi);
505  }
506  if (bbi->fail != UT64_MAX) {
507  nodes++;
508  printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color=\"%s\"];\n",
509  bbi->addr, bbi->fail, pal_fail);
510  print_color_node(core, bbi);
511  }
512  if (bbi->switch_op) {
513  RzAnalysisCaseOp *caseop;
514  RzListIter *iter;
515 
516  if (bbi->fail != UT64_MAX) {
517  printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color=\"%s\"];\n",
518  bbi->addr, bbi->fail, pal_fail);
519  print_color_node(core, bbi);
520  }
521  rz_list_foreach (bbi->switch_op->cases, iter, caseop) {
522  nodes++;
523  printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color2=\"%s\"];\n",
524  caseop->addr, caseop->jump, pal_fail);
525  print_color_node(core, bbi);
526  }
527  }
528  }
529  return nodes;
530 }
static void print_color_node(RzCore *core, RzAnalysisBlock *bbi)
Definition: gdiff.c:349
RzAnalysisSwitchOp * switch_op
Definition: rz_analysis.h:874

References rz_analysis_case_obj_t::addr, rz_analysis_bb_t::addr, rz_analysis_function_t::bbs, rz_analysis_switch_obj_t::cases, rz_analysis_bb_t::fail, rz_analysis_case_obj_t::jump, rz_analysis_bb_t::jump, PFMT64x, print_color_node(), printf(), rz_analysis_bb_t::switch_op, and UT64_MAX.

Referenced by draw_graph_nodes().

◆ graph_construct_nodes()

static int graph_construct_nodes ( RzCore core,
RzCore core2,
RzAnalysisFunction fcn,
PJ pj 
)
static

Definition at line 358 of file gdiff.c.

358  {
359  char addr_a[32], addr_b[32];
360 
361  RzAnalysisBlock *bbi;
362  RzListIter *iter;
363  int is_json = pj != NULL;
364  const char *font = rz_config_get(core->config, "graph.font");
365  int nodes = 0;
366 
367  snprintf(addr_a, sizeof(addr_a), "0x%08" PFMT64x, fcn->addr);
368  snprintf(addr_b, sizeof(addr_b), "0x%08" PFMT64x, fcn->diff->addr);
369 
370  const char *norig = fcn->name ? fcn->name : addr_a;
371  const char *nmodi = fcn->diff->name ? fcn->diff->name : addr_b;
372 
373  rz_list_foreach (fcn->bbs, iter, bbi) {
374  if (is_json) {
375  RzDebugTracepoint *t = rz_debug_trace_get(core->dbg, bbi->addr);
376  ut8 *buf = malloc(bbi->size);
377  pj_o(pj);
378  pj_kn(pj, "offset", bbi->addr);
379  pj_kn(pj, "size", bbi->size);
380  if (bbi->jump != UT64_MAX) {
381  pj_kn(pj, "jump", bbi->jump);
382  }
383  if (bbi->fail != -1) {
384  pj_kn(pj, "fail", bbi->fail);
385  }
386  if (bbi->switch_op) {
388  pj_k(pj, "switchop");
389  pj_o(pj);
390  pj_kn(pj, "offset", op->addr);
391  pj_kn(pj, "defval", op->def_val);
392  pj_kn(pj, "maxval", op->max_val);
393  pj_kn(pj, "minval", op->min_val);
394  pj_k(pj, "cases");
395  pj_a(pj);
396  RzAnalysisCaseOp *case_op;
397  RzListIter *case_iter;
398  rz_list_foreach (op->cases, case_iter, case_op) {
399  pj_o(pj);
400  pj_kn(pj, "offset", case_op->addr);
401  pj_kn(pj, "value", case_op->value);
402  pj_kn(pj, "jump", case_op->jump);
403  pj_end(pj);
404  }
405  pj_end(pj);
406  pj_end(pj);
407  }
408  if (t) {
409  pj_k(pj, "trace");
410  pj_o(pj);
411  pj_ki(pj, "count", t->count);
412  pj_ki(pj, "times", t->times);
413  pj_end(pj);
414  }
415  pj_kn(pj, "colorize", bbi->colorize);
416  pj_k(pj, "ops");
417  pj_a(pj);
418  if (buf) {
419  rz_io_read_at(core->io, bbi->addr, buf, bbi->size);
420  rz_core_print_disasm_json(core, bbi->addr, buf, bbi->size, 0, pj);
421  free(buf);
422  } else {
423  eprintf("cannot allocate %" PFMT64u " byte(s)\n", bbi->size);
424  }
425  pj_end(pj);
426  pj_end(pj);
427  continue;
428  } else {
429  const char *fillcolor = diff_color(bbi);
430  nodes++;
432  rz_config_hold_i(hc, "scr.color", "scr.utf8", "asm.offset", "asm.lines",
433  "asm.cmt.right", "asm.lines.fcn", "asm.bytes", "asm.comments", NULL);
434  rz_config_set_i(core->config, "scr.utf8", 0);
435  rz_config_set_i(core->config, "asm.offset", 0);
436  rz_config_set_i(core->config, "asm.lines", 0);
437  rz_config_set_i(core->config, "asm.cmt.right", 0);
438  rz_config_set_i(core->config, "asm.lines.fcn", 0);
439  rz_config_set_i(core->config, "asm.bytes", 0);
440  rz_config_set_i(core->config, "asm.comments", 0);
441  rz_config_set_i(core->config, "scr.color", COLOR_MODE_DISABLED);
442 
443  char *original = rz_core_cmd_strf(core, "pdb @ 0x%08" PFMT64x, bbi->addr);
444 
445  if (bbi->diff && bbi->diff->type == RZ_ANALYSIS_DIFF_TYPE_UNMATCH) {
446  RzConfig *oc = core2->config;
447  core2->config = core->config;
448 
449  char *modified = rz_core_cmd_strf(core2, "pdb @ 0x%08" PFMT64x, bbi->diff->addr);
450  if (!modified || !strcmp(original, modified)) {
451  // sometimes the mismatch is on a call value
452  // but the output is actually the same due sym./imp.
453  free(modified);
454  core2->config = oc;
455  goto graph_construct_nodes_is_same;
456  }
457 
458  RzDiff *dff = rz_diff_lines_new(original, modified, NULL);
459  char *diffstr = rz_diff_unified_text(dff, norig, nmodi, false, false);
460  rz_diff_free(dff);
461 
462  rz_str_replace_char(diffstr, '"', '\'');
463  diffstr = rz_str_replace(diffstr, "\n", "\\l", 1);
464  printf("\t\"0x%08" PFMT64x "\" [fillcolor=\"%s\","
465  "color=\"black\", fontname=\"%s\","
466  " label=\"%s\", URL=\"%s/0x%08" PFMT64x "\"]\n",
467  bbi->addr, fillcolor, font, diffstr, fcn->name,
468  bbi->addr);
469  free(diffstr);
470  free(modified);
471  core2->config = oc;
472  } else {
473  graph_construct_nodes_is_same:
474 
475  rz_str_replace_char(original, '"', '\'');
476  original = rz_str_replace(original, "\n", "\\l", 1);
477  printf("\t\"0x%08" PFMT64x "\" [fillcolor=\"%s\","
478  "color=\"black\", fontname=\"%s\","
479  " label=\"%s\", URL=\"%s/0x%08" PFMT64x "\"]\n",
480  bbi->addr, fillcolor, font, original, fcn->name, bbi->addr);
481  }
482  free(original);
483  rz_config_set_i(core->config, "scr.color", 1);
486  }
487  }
488  return nodes;
489 }
RZ_API char * rz_core_cmd_strf(RzCore *core, const char *fmt,...)
Definition: cmd.c:5472
RZ_API RzConfigNode * rz_config_set_i(RzConfig *cfg, RZ_NONNULL const char *name, const ut64 i)
Definition: config.c:419
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:75
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 void rz_diff_free(RZ_NULLABLE RzDiff *diff)
frees the diff structure
Definition: diff.c:295
RZ_API int rz_core_print_disasm_json(RzCore *core, ut64 addr, ut8 *buf, int nb_bytes, int nb_opcodes, PJ *pj)
Definition: disasm.c:6040
static const char * diff_color(RzAnalysisBlock *bbi)
Definition: gdiff.c:334
RZ_API void rz_config_hold_restore(RzConfigHold *h)
Restore whatever config options were previously saved in h.
Definition: hold.c:132
RZ_API RzConfigHold * rz_config_hold_new(RzConfig *cfg)
Create an opaque object to save/restore some configuration options.
Definition: hold.c:116
RZ_API bool rz_config_hold_i(RzConfigHold *h,...)
Save the current values of a list of config options that have integer values.
Definition: hold.c:81
RZ_API void rz_config_hold_free(RzConfigHold *h)
Free a RzConfigHold object h.
Definition: hold.c:152
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
void * malloc(size_t size)
Definition: malloc.c:123
#define eprintf(x, y...)
Definition: rlcc.c:7
@ COLOR_MODE_DISABLED
Definition: rz_cons.h:442
RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, int len)
Definition: io.c:300
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
Definition: str.c:1110
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
#define PFMT64u
Definition: rz_types.h:395
RzAnalysisDiff * diff
Definition: rz_analysis.h:263
RzDebug * dbg
Definition: rz_core.h:329
RzIO * io
Definition: rz_core.h:313
RzConfig * config
Definition: rz_core.h:300
Definition: diff.c:89
RZ_API RzDebugTracepoint * rz_debug_trace_get(RzDebug *dbg, ut64 addr)
Definition: trace.c:200
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
Definition: dis.c:32

References rz_analysis_diff_t::addr, rz_analysis_function_t::addr, rz_analysis_case_obj_t::addr, rz_analysis_bb_t::addr, rz_analysis_function_t::bbs, COLOR_MODE_DISABLED, rz_analysis_bb_t::colorize, rz_core_t::config, rz_debug_tracepoint_t::count, rz_core_t::dbg, rz_analysis_function_t::diff, rz_analysis_bb_t::diff, diff_color(), eprintf, rz_analysis_bb_t::fail, free(), rz_core_t::io, rz_analysis_case_obj_t::jump, rz_analysis_bb_t::jump, malloc(), rz_analysis_diff_t::name, rz_analysis_function_t::name, NULL, PFMT64u, PFMT64x, pj_a(), pj_end(), pj_k(), pj_ki(), pj_kn(), pj_o(), printf(), RZ_ANALYSIS_DIFF_TYPE_UNMATCH, rz_config_get(), rz_config_hold_free(), rz_config_hold_i(), rz_config_hold_new(), rz_config_hold_restore(), rz_config_set_i(), rz_core_cmd_strf(), rz_core_print_disasm_json(), rz_debug_trace_get(), rz_diff_free(), rz_diff_lines_new(), rz_diff_unified_text(), rz_io_read_at(), rz_str_replace(), rz_str_replace_char(), rz_analysis_bb_t::size, snprintf, rz_analysis_bb_t::switch_op, rz_debug_tracepoint_t::times, rz_analysis_diff_t::type, UT64_MAX, and rz_analysis_case_obj_t::value.

Referenced by draw_graph_nodes().

◆ print_color_node()

static void print_color_node ( RzCore core,
RzAnalysisBlock bbi 
)
static

Definition at line 349 of file gdiff.c.

349  {
350  bool color_current = rz_config_get_i(core->config, "graph.gv.current");
351  bool current = rz_analysis_block_contains(bbi, core->offset);
352  if (current && color_current) {
353  printf("\t\"0x%08" PFMT64x "\" ", bbi->addr);
354  printf("\t[fillcolor=gray style=filled shape=box];\n");
355  }
356 }
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
ut64 offset
Definition: rz_core.h:301

References rz_analysis_bb_t::addr, rz_core_t::config, rz_core_t::offset, PFMT64x, printf(), and rz_config_get_i().

Referenced by graph_construct_edges().

◆ rz_core_diff_show()

RZ_API void rz_core_diff_show ( RzCore c,
RzCore c2,
bool  json 
)

Definition at line 161 of file gdiff.c.

161  {
162  rz_return_if_fail(c && c2);
163  bool color = rz_config_get_i(c->config, "scr.color") > 0 || rz_config_get_i(c2->config, "scr.color") > 0;
164  bool bare = rz_config_get_b(c->config, "diff.bare") || rz_config_get_b(c2->config, "diff.bare");
165  bool ignore = false;
166  RzList *fcns = rz_analysis_get_fcns(c->analysis);
167  RzListIter *iter;
169  int maxnamelen = 0;
170  ut64 maxsize = 0;
171  int digits = 1;
172  int len;
173  PJ *pj = NULL;
174 
175  if (json) {
176  pj = pj_new();
177  if (!pj) {
178  eprintf("cannot alocate json\n");
179  return;
180  }
181  pj_a(pj);
182  }
183 
184  rz_list_foreach (fcns, iter, f) {
185  if (f->name && (len = strlen(f->name)) > maxnamelen) {
186  maxnamelen = len;
187  }
188  if (rz_analysis_function_realsize(f) > maxsize) {
189  maxsize = rz_analysis_function_realsize(f);
190  }
191  }
192  fcns = rz_analysis_get_fcns(c2->analysis);
193  rz_list_foreach (fcns, iter, f) {
194  if (f->name && (len = strlen(f->name)) > maxnamelen) {
195  maxnamelen = len;
196  }
197  if (rz_analysis_function_realsize(f) > maxsize) {
198  maxsize = rz_analysis_function_realsize(f);
199  }
200  }
201  while (maxsize > 9) {
202  maxsize /= 10;
203  digits++;
204  }
205 
206  fcns = rz_analysis_get_fcns(c->analysis);
207  if (rz_list_empty(fcns)) {
208  eprintf("functions list is empty. analyze the binary first\n");
209  pj_free(pj);
210  return;
211  }
212  rz_list_sort(fcns, c->analysis->columnSort);
213 
214  rz_list_foreach (fcns, iter, f) {
215  switch (f->type) {
218  switch (f->diff->type) {
221  ignore = false;
222  break;
223  default:
224  ignore = true;
225  break;
226  }
227  if (ignore) {
228  continue;
229  }
230  if (json) {
231  double dist = f->diff->dist;
232  pj_o(pj);
233  pj_kd(pj, "distance", f->diff->dist);
234  pj_ks(pj, "type", dist >= 1.0 ? "MATCH" : (dist >= 0.5 ? "SIMILAR" : "UNMATCH"));
235  if (f->name) {
236  pj_ko(pj, "original");
237  pj_ks(pj, "name", f->name);
238  pj_kn(pj, "addr", f->addr);
239  pj_kn(pj, "size", rz_analysis_function_realsize(f));
240  pj_end(pj);
241  }
242  if (f->diff->name) {
243  pj_ko(pj, "modified");
244  pj_ks(pj, "name", f->diff->name);
245  pj_kn(pj, "addr", f->diff->addr);
246  pj_kn(pj, "size", f->diff->size);
247  pj_end(pj);
248  }
249  pj_end(pj);
250  } else {
251  diffrow(f->addr, f->name, rz_analysis_function_realsize(f), maxnamelen, digits,
252  f->diff->addr, f->diff->name, f->diff->size,
253  f->diff->dist, bare, color);
254  }
255  break;
256  }
257  }
258 
259  ignore = true;
260  rz_list_foreach (fcns, iter, f) {
261  switch (f->type) {
264  if (f->diff->type == RZ_ANALYSIS_DIFF_TYPE_NULL) {
265  if (json) {
266  pj_o(pj);
267  pj_kd(pj, "distance", 0.0);
268  pj_ks(pj, "type", "NEW");
269  if (f->name) {
270  pj_ko(pj, "original");
271  pj_ks(pj, "name", f->name);
272  pj_kn(pj, "addr", f->addr);
273  pj_kn(pj, "size", rz_analysis_function_realsize(f));
274  pj_end(pj);
275  }
276  pj_end(pj);
277  } else {
278  if (ignore) {
279  ignore = false;
280  printf("original not matched:");
281  }
282  printf(" %s", f->name);
283  }
284  }
285  break;
286  }
287  }
288  if (!json && !ignore) {
289  printf("\n");
290  }
291 
292  fcns = rz_analysis_get_fcns(c2->analysis);
293  rz_list_sort(fcns, c2->analysis->columnSort);
294 
295  ignore = true;
296  rz_list_foreach (fcns, iter, f) {
297  switch (f->type) {
300  if (f->diff->type == RZ_ANALYSIS_DIFF_TYPE_NULL) {
301  if (json) {
302  pj_o(pj);
303  pj_kd(pj, "distance", 0.0);
304  pj_ks(pj, "type", "NEW");
305  if (f->name) {
306  pj_ko(pj, "modified");
307  pj_ks(pj, "name", f->name);
308  pj_kn(pj, "addr", f->addr);
309  pj_kn(pj, "size", rz_analysis_function_realsize(f));
310  pj_end(pj);
311  }
312  pj_end(pj);
313  } else {
314  if (ignore) {
315  ignore = false;
316  printf("modified not matched:");
317  }
318  printf(" %s", f->name);
319  }
320  }
321  break;
322  }
323  }
324 
325  if (json) {
326  pj_end(pj);
327  printf("%s\n", pj_string(pj));
328  pj_free(pj);
329  } else if (!ignore) {
330  printf("\n");
331  }
332 }
size_t len
Definition: 6502dis.c:15
RZ_API ut64 rz_analysis_function_realsize(const RzAnalysisFunction *fcn)
Definition: function.c:338
RZ_API RzList * rz_analysis_get_fcns(RzAnalysis *analysis)
Definition: analysis.c:392
lsl lsr asr ror lsl lsr asr ror lsl lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror c2
RZ_API bool rz_config_get_b(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:142
static void diffrow(ut64 addr, const char *name, ut32 size, int maxnamelen, int digits, ut64 addr2, const char *name2, ut32 size2, double dist, bool bare, bool color)
Definition: gdiff.c:124
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_ANALYSIS_DIFF_TYPE_NULL
Definition: rz_analysis.h:205
@ RZ_ANALYSIS_FCN_TYPE_SYM
Definition: rz_analysis.h:195
@ RZ_ANALYSIS_FCN_TYPE_FCN
Definition: rz_analysis.h:193
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
RZ_API PJ * pj_ko(PJ *j, const char *k)
Definition: pj.c:156
RZ_API PJ * pj_new(void)
Definition: pj.c:25
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_kd(PJ *j, const char *k, double d)
Definition: pj.c:136
#define f(i)
Definition: sha256.c:46
#define c(i)
Definition: sha256.c:43
Definition: rz_pj.h:12
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References c, c2, color, diffrow(), eprintf, f, len, NULL, pj_a(), pj_end(), pj_free(), pj_kd(), pj_kn(), pj_ko(), pj_ks(), pj_new(), pj_o(), pj_string(), printf(), RZ_ANALYSIS_DIFF_TYPE_MATCH, RZ_ANALYSIS_DIFF_TYPE_NULL, RZ_ANALYSIS_DIFF_TYPE_UNMATCH, RZ_ANALYSIS_FCN_TYPE_FCN, RZ_ANALYSIS_FCN_TYPE_SYM, rz_analysis_function_realsize(), rz_analysis_get_fcns(), rz_config_get_b(), rz_config_get_i(), rz_list_sort(), rz_return_if_fail, and ut64().

Referenced by rz_diff_graphs_files().

◆ rz_core_diff_show_function()

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.

Each node that doesn't match 100% with the other function will include a unified diff of the assembly of the same basic block.

Definition at line 574 of file gdiff.c.

574  {
575  rz_return_val_if_fail(core && core2, false);
576  const char *font = rz_config_get(core->config, "graph.font");
577 
578  int nodes = 0;
579  PJ *pj = NULL;
581  if (!fcn) {
582  eprintf("cannot get functions at 0x%" PFMT64x "\n", addr1);
583  return false;
584  }
585 
586  if (!json) {
587  const char *gv_edge = rz_config_get(core->config, "graph.gv.edge");
588  const char *gv_node = rz_config_get(core->config, "graph.gv.node");
589  const char *gv_spline = rz_config_get(core->config, "graph.gv.spline");
590  if (!gv_edge || !*gv_edge) {
591  gv_edge = "arrowhead=\"normal\"";
592  }
593  if (!gv_node || !*gv_node) {
594  gv_node = "fillcolor=gray style=filled shape=box";
595  }
596  if (!gv_spline || !*gv_spline) {
597  gv_spline = "splines=\"ortho\"";
598  }
599  printf("digraph code {\n"
600  "\tgraph [bgcolor=azure fontsize=8 fontname=\"%s\" %s];\n"
601  "\tnode [%s];\n"
602  "\tedge [%s];\n",
603  font, gv_spline, gv_node, gv_edge);
604  } else {
605  pj = pj_new();
606  if (!pj) {
607  return false;
608  }
609  pj_a(pj);
610  }
611  nodes += draw_graph_nodes(core, core2, fcn, pj);
612  if (nodes < 1 && !json) {
613  printf("\t\"0x%08" PFMT64x "\";\n", addr1);
614  }
615  if (json) {
616  pj_end(pj);
617  printf("%s\n", pj_string(pj));
618  pj_free(pj);
619  } else {
620  printf("}\n");
621  }
622  return true;
623 }
RZ_API RzAnalysisFunction * rz_analysis_get_function_at(RzAnalysis *analysis, ut64 addr)
Definition: function.c:184
static int draw_graph_nodes(RzCore *core, RzCore *core2, RzAnalysisFunction *fcn, PJ *pj)
Definition: gdiff.c:532

References rz_core_t::analysis, rz_core_t::config, draw_graph_nodes(), eprintf, NULL, PFMT64x, pj_a(), pj_end(), pj_free(), pj_new(), pj_string(), printf(), rz_analysis_get_function_at(), rz_config_get(), and rz_return_val_if_fail.

Referenced by rz_diff_graphs_files().

◆ rz_core_gdiff_2_files()

RZ_API bool rz_core_gdiff_2_files ( RzCore c,
RzCore c2 
)

Calculates basic block differences of all functions within 2 files.

Calculates basic block differences of all functions within 2 files.

Definition at line 89 of file gdiff.c.

89  {
90  rz_return_val_if_fail(c && c2, false);
91  RzCore *cores[2] = { c, c2 };
92  RzAnalysisFunction *fcn;
93  RzAnalysisBlock *bb;
94  RzListIter *iter, *iter2;
95  int i;
96 
97  if (!c || !c2) {
98  return false;
99  }
100  for (i = 0; i < 2; i++) {
101  /* remove strings */
102  rz_list_foreach_safe (cores[i]->analysis->fcns, iter, iter2, fcn) {
103  if (!strncmp(fcn->name, "str.", 4)) {
105  }
106  }
107  /* Fingerprint fcn bbs (functions basic-blocks) */
108  rz_list_foreach (cores[i]->analysis->fcns, iter, fcn) {
109  rz_list_foreach (fcn->bbs, iter2, bb) {
110  rz_analysis_diff_fingerprint_bb(cores[i]->analysis, bb);
111  }
112  }
113  /* Fingerprint fcn */
114  rz_list_foreach (cores[i]->analysis->fcns, iter, fcn) {
115  rz_analysis_diff_fingerprint_fcn(cores[i]->analysis, fcn);
116  }
117  }
118  /* Diff functions */
119  rz_analysis_diff_fcn(cores[0]->analysis, cores[0]->analysis->fcns, cores[1]->analysis->fcns);
120 
121  return true;
122 }
RZ_API size_t rz_analysis_diff_fingerprint_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn)
Definition: diff.c:91
RZ_API int rz_analysis_diff_fingerprint_bb(RzAnalysis *analysis, RzAnalysisBlock *bb)
Definition: diff.c:49
RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList *fcns1, RzList *fcns2)
Definition: diff.c:176
RZ_API bool rz_analysis_function_delete(RzAnalysisFunction *fcn)
Definition: function.c:180
lzma_index ** i
Definition: index.h:629

References rz_core_t::analysis, rz_analysis_function_t::bbs, c, c2, rz_analysis_t::fcns, i, rz_analysis_function_t::name, rz_analysis_diff_fcn(), rz_analysis_diff_fingerprint_bb(), rz_analysis_diff_fingerprint_fcn(), rz_analysis_function_delete(), and rz_return_val_if_fail.

Referenced by rz_diff_graphs_files().

◆ rz_core_gdiff_function_1_file()

RZ_API bool rz_core_gdiff_function_1_file ( RzCore c,
ut64  addr,
ut64  addr2 
)

Calculates basic block differences of 2 functions within the same file.

Calculates basic block differences of 2 functions within the same file

Definition at line 17 of file gdiff.c.

17  {
18  RzList *la, *lb;
20  RzAnalysisFunction *fb = rz_analysis_get_function_at(c->analysis, addr2);
21  if (!fa || !fb) {
22  return false;
23  }
24  RzAnalysisBlock *bb;
26  rz_list_foreach (fa->bbs, iter, bb) {
27  rz_analysis_diff_fingerprint_bb(c->analysis, bb);
28  }
29  rz_list_foreach (fb->bbs, iter, bb) {
30  rz_analysis_diff_fingerprint_bb(c->analysis, bb);
31  }
32  la = rz_list_new();
33  rz_list_append(la, fa);
34  lb = rz_list_new();
35  rz_list_append(lb, fb);
36  rz_analysis_diff_fcn(c->analysis, la, lb);
37  rz_list_free(la);
38  rz_list_free(lb);
39  return true;
40 }
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137

References addr, rz_analysis_function_t::bbs, c, rz_analysis_diff_fcn(), rz_analysis_diff_fingerprint_bb(), rz_analysis_get_function_at(), rz_list_append(), rz_list_free(), and rz_list_new().

Referenced by cmd_analysis_graph().

◆ rz_core_gdiff_function_2_files()

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.

Calculates basic block differences of 2 functions within 2 files

Definition at line 47 of file gdiff.c.

47  {
48  rz_return_val_if_fail(c && c2, false);
49  RzList *la, *lb;
51  RzAnalysisFunction *fb = rz_analysis_get_function_at(c2->analysis, addr2);
52  if (!fa || !fb) {
53  eprintf("cannot get functions at 0x%" PFMT64x " or at 0x%" PFMT64x "\n", addr, addr2);
54  return false;
55  }
56  RzAnalysisBlock *bb;
58  rz_list_foreach (fa->bbs, iter, bb) {
59  if (rz_analysis_diff_fingerprint_bb(c->analysis, bb) < 0) {
60  eprintf("cannot fingerprint 0x%" PFMT64x "\n", addr);
61  return false;
62  }
63  }
64  rz_list_foreach (fb->bbs, iter, bb) {
65  if (rz_analysis_diff_fingerprint_bb(c2->analysis, bb) < 0) {
66  eprintf("cannot fingerprint 0x%" PFMT64x "\n", addr2);
67  return false;
68  }
69  }
70 
71  rz_analysis_diff_fingerprint_fcn(c->analysis, fa);
72  rz_analysis_diff_fingerprint_fcn(c2->analysis, fb);
73 
74  la = rz_list_new();
75  rz_list_append(la, fa);
76  lb = rz_list_new();
77  rz_list_append(lb, fb);
78  rz_analysis_diff_fcn(c->analysis, la, lb);
79  rz_list_free(la);
80  rz_list_free(lb);
81  return true;
82 }

References addr, rz_analysis_function_t::bbs, c, c2, eprintf, PFMT64x, rz_analysis_diff_fcn(), rz_analysis_diff_fingerprint_bb(), rz_analysis_diff_fingerprint_fcn(), rz_analysis_get_function_at(), rz_list_append(), rz_list_free(), rz_list_new(), and rz_return_val_if_fail.

Referenced by rz_diff_graphs_files().