Add graph diffing and better function diffing (#1131)
* Added function diffing and graph diffing (json and dot only) * Added tests for new functions and graph diffing * diff graph more clear * enforce same colors everywhere. * using realsize for calculating function size * renaming unconditional jump color name * fixed memory issues and weird behaviour
This commit is contained in:
parent
52ca5f8093
commit
1348c247df
49 changed files with 762 additions and 348 deletions
|
|
@ -51,17 +51,17 @@ RZ_API int rz_analysis_diff_fingerprint_bb(RzAnalysis *analysis, RzAnalysisBlock
|
|||
int oplen, idx = 0;
|
||||
|
||||
if (!analysis) {
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
if (analysis->cur && analysis->cur->fingerprint_bb) {
|
||||
return (analysis->cur->fingerprint_bb(analysis, bb));
|
||||
}
|
||||
if (!(bb->fingerprint = malloc(1 + bb->size))) {
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
if (!(buf = malloc(bb->size + 1))) {
|
||||
free(bb->fingerprint);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
if (analysis->iob.read_at(analysis->iob.io, bb->addr, buf, bb->size)) {
|
||||
memcpy(bb->fingerprint, buf, bb->size);
|
||||
|
|
@ -69,7 +69,7 @@ RZ_API int rz_analysis_diff_fingerprint_bb(RzAnalysis *analysis, RzAnalysisBlock
|
|||
if (!(op = rz_analysis_op_new())) {
|
||||
free(bb->fingerprint);
|
||||
free(buf);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
while (idx < bb->size) {
|
||||
if ((oplen = rz_analysis_op(analysis, op, 0, buf + idx, bb->size - idx, RZ_ANALYSIS_OP_MASK_BASIC)) < 1) {
|
||||
|
|
@ -156,6 +156,7 @@ RZ_API bool rz_analysis_diff_bb(RzAnalysis *analysis, RzAnalysisFunction *fcn, R
|
|||
fcn->diff->type = fcn2->diff->type =
|
||||
RZ_ANALYSIS_DIFF_TYPE_UNMATCH;
|
||||
}
|
||||
mbb->diff->dist = mbb2->diff->dist = ot;
|
||||
RZ_FREE(mbb->fingerprint);
|
||||
RZ_FREE(mbb2->fingerprint);
|
||||
mbb->diff->addr = mbb2->addr;
|
||||
|
|
@ -193,7 +194,7 @@ RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList *fcns, RzList *fcns
|
|||
rz_diff_levenstein_distance(fcn->fingerprint, fcn->fingerprint_size,
|
||||
fcn2->fingerprint, fcn2->fingerprint_size, NULL, &t);
|
||||
/* Set flag in matched functions */
|
||||
fcn->diff->type = fcn2->diff->type = (t >= 1)
|
||||
fcn->diff->type = fcn2->diff->type = (t >= 1.0)
|
||||
? RZ_ANALYSIS_DIFF_TYPE_MATCH
|
||||
: RZ_ANALYSIS_DIFF_TYPE_UNMATCH;
|
||||
fcn->diff->dist = fcn2->diff->dist = t;
|
||||
|
|
@ -201,8 +202,8 @@ RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList *fcns, RzList *fcns
|
|||
RZ_FREE(fcn2->fingerprint);
|
||||
fcn->diff->addr = fcn2->addr;
|
||||
fcn2->diff->addr = fcn->addr;
|
||||
fcn->diff->size = rz_analysis_function_linear_size(fcn2);
|
||||
fcn2->diff->size = rz_analysis_function_linear_size(fcn);
|
||||
fcn->diff->size = rz_analysis_function_realsize(fcn2);
|
||||
fcn2->diff->size = rz_analysis_function_realsize(fcn);
|
||||
RZ_FREE(fcn->diff->name);
|
||||
if (fcn2->name) {
|
||||
fcn->diff->name = strdup(fcn2->name);
|
||||
|
|
@ -218,21 +219,14 @@ RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList *fcns, RzList *fcns
|
|||
}
|
||||
/* Compare remaining functions */
|
||||
rz_list_foreach (fcns, iter, fcn) {
|
||||
/*
|
||||
if ((fcn->type != RZ_ANALYSIS_FCN_TYPE_FCN &&
|
||||
fcn->type != RZ_ANALYSIS_FCN_TYPE_SYM) ||
|
||||
fcn->diff->type != RZ_ANALYSIS_DIFF_TYPE_NULL) {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
if (fcn->diff->type != RZ_ANALYSIS_DIFF_TYPE_NULL) {
|
||||
continue;
|
||||
}
|
||||
ot = 0;
|
||||
mfcn = mfcn2 = NULL;
|
||||
rz_list_foreach (fcns2, iter2, fcn2) {
|
||||
ut64 fcn_size = rz_analysis_function_linear_size(fcn);
|
||||
ut64 fcn2_size = rz_analysis_function_linear_size(fcn2);
|
||||
ut64 fcn_size = rz_analysis_function_realsize(fcn);
|
||||
ut64 fcn2_size = rz_analysis_function_realsize(fcn2);
|
||||
if (fcn_size > fcn2_size) {
|
||||
maxsize = fcn_size;
|
||||
minsize = fcn2_size;
|
||||
|
|
@ -241,11 +235,9 @@ RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList *fcns, RzList *fcns
|
|||
minsize = fcn_size;
|
||||
}
|
||||
if (maxsize * analysis->diff_thfcn > minsize) {
|
||||
eprintf("Exceeded analysis threshold while diffing %s and %s\n", fcn->name, fcn2->name);
|
||||
continue;
|
||||
}
|
||||
if (fcn2->diff->type != RZ_ANALYSIS_DIFF_TYPE_NULL) {
|
||||
eprintf("Function %s already diffed\n", fcn2->name);
|
||||
continue;
|
||||
}
|
||||
if ((fcn2->type != RZ_ANALYSIS_FCN_TYPE_FCN && fcn2->type != RZ_ANALYSIS_FCN_TYPE_SYM)) {
|
||||
|
|
@ -272,8 +264,8 @@ RZ_API int rz_analysis_diff_fcn(RzAnalysis *analysis, RzList *fcns, RzList *fcns
|
|||
RZ_FREE(mfcn2->fingerprint);
|
||||
mfcn->diff->addr = mfcn2->addr;
|
||||
mfcn2->diff->addr = mfcn->addr;
|
||||
mfcn->diff->size = rz_analysis_function_linear_size(mfcn2);
|
||||
mfcn2->diff->size = rz_analysis_function_linear_size(mfcn);
|
||||
mfcn->diff->size = rz_analysis_function_realsize(mfcn2);
|
||||
mfcn2->diff->size = rz_analysis_function_realsize(mfcn);
|
||||
RZ_FREE(mfcn->diff->name);
|
||||
if (mfcn2->name) {
|
||||
mfcn->diff->name = strdup(mfcn2->name);
|
||||
|
|
|
|||
|
|
@ -1757,7 +1757,7 @@ RZ_API RZ_OWN char *rz_analysis_function_get_signature(RzAnalysisFunction *funct
|
|||
char *args = strdup("");
|
||||
for (i = 0; i < argc; i++) {
|
||||
const char *arg_name = rz_type_func_args_name(a->typedb, realname, i);
|
||||
const char *arg_type = rz_type_func_args_type(a->typedb, realname, i);
|
||||
char *arg_type = rz_type_func_args_type(a->typedb, realname, i);
|
||||
// Here we check if the type is a pointer, in this case we don't put
|
||||
// the space between type and name for the style reasons
|
||||
// "char *var" looks much better than "char * var"
|
||||
|
|
@ -1766,6 +1766,7 @@ RZ_API RZ_OWN char *rz_analysis_function_get_signature(RzAnalysisFunction *funct
|
|||
? rz_str_newf("%s%s%s%s", args, arg_type, maybe_space, arg_name)
|
||||
: rz_str_newf("%s%s%s%s, ", args, arg_type, maybe_space, arg_name);
|
||||
free(args);
|
||||
free(arg_type);
|
||||
args = new_args;
|
||||
}
|
||||
char *signature = rz_str_newf("%s %s (%s);", ret_type ? ret_type : "void", realname, args);
|
||||
|
|
|
|||
|
|
@ -47,10 +47,17 @@ RZ_API bool rz_analysis_function_rebase_vars(RzAnalysis *a, RzAnalysisFunction *
|
|||
// remove all other vars that are overlapped by var and are at the offset of one of its struct members
|
||||
static void shadow_var_struct_members(RzAnalysisVar *var) {
|
||||
RzBaseType *btype = rz_type_db_get_base_type(var->fcn->analysis->typedb, var->type);
|
||||
if (!btype || btype->kind != RZ_BASE_TYPE_KIND_STRUCT) {
|
||||
if (!btype) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (btype->kind != RZ_BASE_TYPE_KIND_STRUCT) {
|
||||
rz_type_base_type_free(btype);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rz_vector_empty(&btype->struct_data.members)) {
|
||||
rz_type_base_type_free(btype);
|
||||
return;
|
||||
}
|
||||
RzTypeStructMember *member;
|
||||
|
|
@ -62,6 +69,7 @@ static void shadow_var_struct_members(RzAnalysisVar *var) {
|
|||
}
|
||||
}
|
||||
}
|
||||
rz_type_base_type_free(btype);
|
||||
}
|
||||
|
||||
RZ_API RzAnalysisVar *rz_analysis_function_set_var(RzAnalysisFunction *fcn, int delta, char kind, RZ_NULLABLE const char *type, int size, bool isarg, RZ_NONNULL const char *name) {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ static void apply_line_style(RzConsCanvas *c, int x, int y, int x2, int y2,
|
|||
RzCons *cons = rz_cons_singleton();
|
||||
switch (style->color) {
|
||||
case LINE_UNCJMP:
|
||||
c->attr = cons->context->pal.graph_trufae;
|
||||
c->attr = cons->context->pal.graph_ujump;
|
||||
break;
|
||||
case LINE_TRUE:
|
||||
c->attr = cons->context->pal.graph_true;
|
||||
|
|
@ -63,7 +63,7 @@ static void apply_line_style(RzConsCanvas *c, int x, int y, int x2, int y2,
|
|||
break;
|
||||
case LINE_NONE:
|
||||
default:
|
||||
c->attr = cons->context->pal.graph_trufae;
|
||||
c->attr = cons->context->pal.graph_ujump;
|
||||
break;
|
||||
}
|
||||
if (!c->color) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ ec graph.box4 rgb:66d9ef
|
|||
ec graph.current rgb:fff
|
||||
ec graph.false rgb:f07178 # false line on visual graph mode
|
||||
ec graph.true rgb:bae67e # true line on visual graph mode
|
||||
ec graph.trufae rgb:55b4d4 # lines in graph that does not have true or false
|
||||
ec graph.ujump rgb:55b4d4 # lines in graph that does not have true or false
|
||||
ec help rgb:c2d94c # color of help explanation text
|
||||
ec input rgb:888
|
||||
ec jmp rgb:c2d94c # jmp instructions
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ ec pop yellow
|
|||
ec linehl rgb:004
|
||||
ec graph.true green
|
||||
ec graph.false red
|
||||
ec graph.trufae blue
|
||||
ec graph.ujump blue
|
||||
ec graph.current blue
|
||||
ec graph.traced blue
|
||||
ec graph.box gray
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ ec graph.box3 rgb:af87ff
|
|||
ec graph.box4 rgb:ff005f
|
||||
ec graph.true rgb:00ff5f
|
||||
ec graph.false rgb:ff005f
|
||||
ec graph.trufae rgb:5f87ff
|
||||
ec graph.ujump rgb:5f87ff
|
||||
ec graph.current rgb:5f87ff
|
||||
ec graph.traced rgb:ffff5f
|
||||
ec linehl rgb:1f1f1f
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ ec push white
|
|||
ec ret rgb:777
|
||||
ec swi black red bold
|
||||
ec trap red
|
||||
ec graph.trufae rgb:ddd
|
||||
ec graph.ujump rgb:ddd
|
||||
ec graph.current rgb:f72
|
||||
ec graph.traced rgb:f00
|
||||
ec gui.cflow rgb:f72
|
||||
|
|
|
|||
|
|
@ -70,6 +70,6 @@ ec graph.box3 rgb:ff00ff
|
|||
ec graph.box4 rgb:808080
|
||||
ec graph.true rgb:00ff00
|
||||
ec graph.false rgb:ff0000
|
||||
ec graph.trufae rgb:0000ff # single jump
|
||||
ec graph.ujump rgb:0000ff # single jump
|
||||
ec graph.traced rgb:ffff00
|
||||
ec graph.current rgb:0000ff
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ ec graph.box3 rgb:f0f
|
|||
ec graph.box4 rgb:f0f
|
||||
ec graph.true rgb:f0f
|
||||
ec graph.false rgb:0ff
|
||||
ec graph.trufae rgb:f0f
|
||||
ec graph.ujump rgb:f0f
|
||||
ec graph.current rgb:0ff
|
||||
ec graph.traced rgb:f0f
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ ec graph.box3 rgb:af2
|
|||
ec graph.box4 rgb:af2
|
||||
ec graph.true rgb:4f2
|
||||
ec graph.false rgb:d41
|
||||
ec graph.trufae rgb:4cf
|
||||
ec graph.ujump rgb:4cf
|
||||
ec graph.current rgb:af2
|
||||
ec graph.traced rgb:090
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ ec graph.box3 rgb:e03030
|
|||
ec graph.box4 rgb:005f87
|
||||
ec graph.true rgb:5f8700
|
||||
ec graph.false rgb:e03030
|
||||
ec graph.trufae rgb:005f87
|
||||
ec graph.ujump rgb:005f87
|
||||
ec graph.current rgb:00f0f0
|
||||
ec graph.traced rgb:e03030
|
||||
ec gui.cflow rgb:ffff00
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ ec graph.box3 rgb:040
|
|||
ec graph.box4 rgb:040
|
||||
ec graph.true rgb:06c
|
||||
ec graph.false rgb:035
|
||||
ec graph.trufae rgb:06c
|
||||
ec graph.ujump rgb:06c
|
||||
ec graph.current rgb:99a
|
||||
ec graph.traced rgb:bbb
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ ec graph.box3 rgb:66d9ef
|
|||
ec graph.box4 rgb:66d9ef
|
||||
ec graph.true rgb:009100
|
||||
ec graph.false rgb:bc0000
|
||||
ec graph.trufae rgb:0043cb
|
||||
ec graph.ujump rgb:0043cb
|
||||
ec graph.current rgb:fff
|
||||
|
||||
ec func_var rgb:99a
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ ec graph.box=rgb:9e9e9e
|
|||
ec graph.box2 rgb:5f87d7
|
||||
ec graph.box3 rgb:af5f87
|
||||
ec graph.box4 rgb:303030
|
||||
ec graph.trufae rgb:005fff
|
||||
ec graph.ujump rgb:005fff
|
||||
ec graph.current rgb:c68e00
|
||||
ec graph.true rgb:009100
|
||||
ec graph.false rgb:bc0000
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ ec graph.box3 blue
|
|||
ec graph.box4 blue
|
||||
ec graph.true green
|
||||
ec graph.false red
|
||||
ec graph.trufae blue
|
||||
ec graph.ujump blue
|
||||
ec graph.current blue
|
||||
ec graph.traced red
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ ec graph.box3 rgb:86c06c
|
|||
ec graph.box4 rgb:86c06c
|
||||
ec graph.true rgb:86c06c
|
||||
ec graph.false rgb:e0f8cf
|
||||
ec graph.trufae rgb:86c06c
|
||||
ec graph.ujump rgb:86c06c
|
||||
ec graph.current rgb:e0f8cf
|
||||
ec graph.traced rgb:86c06c
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ ec graph.box3 rgb:30f030
|
|||
ec graph.box4 rgb:30f030
|
||||
ec graph.true rgb:30f030
|
||||
ec graph.false rgb:f03030
|
||||
ec graph.trufae rgb:3030f0
|
||||
ec graph.ujump rgb:3030f0
|
||||
ec graph.current rgb:f03030
|
||||
ec graph.traced rgb:f00000
|
||||
ec gui.cflow rgb:f03030
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ ec graph.box3 rgb:444
|
|||
ec graph.box4 rgb:444
|
||||
ec graph.true rgb:ef2
|
||||
ec graph.false rgb:5d5
|
||||
ec graph.trufae rgb:af2
|
||||
ec graph.ujump rgb:af2
|
||||
ec graph.current rgb:af2
|
||||
ec graph.traced rgb:090
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ ec graph.box3 rgb:ff0000
|
|||
ec graph.box4 rgb:0000ff
|
||||
ec graph.true green
|
||||
ec graph.false rgb:050
|
||||
ec graph.trufae green
|
||||
ec graph.ujump green
|
||||
ec graph.current green
|
||||
ec graph.traced rgb:060
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ ec graph.box3 rgb:66d9ef
|
|||
ec graph.box4 rgb:66d9ef
|
||||
ec graph.true rgb:A6df2E
|
||||
ec graph.false rgb:f92672
|
||||
ec graph.trufae rgb:a398e5
|
||||
ec graph.ujump rgb:a398e5
|
||||
ec graph.current rgb:fff
|
||||
|
||||
ec func_var cyan
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ ec ucall rgb:f72 rgb:333
|
|||
ec ujmp rgb:f72
|
||||
ec graph.true rgb:f72
|
||||
ec graph.false rgb:777
|
||||
ec graph.trufae rgb:ddd
|
||||
ec graph.ujump rgb:ddd
|
||||
ec graph.current rgb:f72
|
||||
ec graph.traced rgb:f00
|
||||
ec graph.box rgb:fff
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ ec graph.box3 rgb:c678dd
|
|||
ec graph.box4 rgb:000000
|
||||
ec graph.true rgb:98c379
|
||||
ec graph.false rgb:e06c75
|
||||
ec graph.trufae rgb:61afef
|
||||
ec graph.ujump rgb:61afef
|
||||
ec graph.current rgb:61afef
|
||||
ec graph.traced rgb:d19a66
|
||||
ec linehl rgb:5c6370
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ ec crypto rgb:75d
|
|||
ec linehl rgb:fdf
|
||||
ec graph.true rgb:f5d
|
||||
ec graph.false rgb:715
|
||||
ec graph.trufae rgb:f5d
|
||||
ec graph.ujump rgb:f5d
|
||||
ec graph.current rgb:f5d
|
||||
ec graph.traced rgb:a7f
|
||||
ec graph.box rgb:f5d
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ ec graph.box3 red
|
|||
ec graph.box4 red
|
||||
ec graph.true green
|
||||
ec graph.false red
|
||||
ec graph.trufae green
|
||||
ec graph.ujump green
|
||||
ec graph.current green
|
||||
ec graph.traced yellow
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ ec wordhl rgb:ff0000
|
|||
ec linehl rgb:210
|
||||
ec graph.true rgb:fd9
|
||||
ec graph.false rgb:431
|
||||
ec graph.trufae rgb:fd9
|
||||
ec graph.ujump rgb:fd9
|
||||
ec graph.current rgb:0000ff
|
||||
ec graph.traced rgb:0000ff
|
||||
ec graph.box rgb:431
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ ec graph.box3 rgb:9df
|
|||
ec graph.box4 rgb:9df
|
||||
ec graph.true rgb:9c4
|
||||
ec graph.false rgb:d66
|
||||
ec graph.trufae rgb:9c4
|
||||
ec graph.ujump rgb:9c4
|
||||
ec graph.current rgb:fff
|
||||
|
||||
ec func_var rgb:9df
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ ec graph.box3 rgb:033
|
|||
ec graph.box4 rgb:033
|
||||
ec graph.true rgb:890
|
||||
ec graph.false rgb:c41
|
||||
ec graph.trufae rgb:899
|
||||
ec graph.ujump rgb:899
|
||||
ec graph.current rgb:f00
|
||||
ec graph.traced red
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ ec linehl rgb:004
|
|||
|
||||
ec graph.true rgb:370
|
||||
ec graph.false rgb:a00
|
||||
ec graph.trufae rgb:bbb
|
||||
ec graph.ujump rgb:bbb
|
||||
ec graph.current rgb:7d1
|
||||
ec graph.traced rgb:f00
|
||||
ec graph.box rgb:950
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ ec flag rgb:ffd
|
|||
ec linehl rgb:004
|
||||
ec graph.true rgb:9b7
|
||||
ec graph.false rgb:b97
|
||||
ec graph.trufae rgb:64c
|
||||
ec graph.ujump rgb:64c
|
||||
ec graph.current blue
|
||||
ec graph.traced blue
|
||||
ec graph.box rgb:9b7
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ ec graph.box3 red
|
|||
ec graph.box4 blue
|
||||
ec graph.true green
|
||||
ec graph.false red
|
||||
ec graph.trufae blue
|
||||
ec graph.ujump blue
|
||||
ec graph.current rgb:0ff
|
||||
ec graph.traced red
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ ec graph.box4 rgb:66d9ef
|
|||
ec graph.current rgb:fff
|
||||
ec graph.false rgb:990000 # false line on visual graph mode
|
||||
ec graph.true rgb:376B4C # true line on visual graph mode
|
||||
ec graph.trufae rgb:007D96 # lines in graph that does not have true or false
|
||||
ec graph.ujump rgb:007D96 # lines in graph that does not have true or false
|
||||
ec help rgb:2F6F9F 0 italic # color of help explanation text
|
||||
ec input rgb:888
|
||||
ec jmp rgb:376B4C 0 bold underline # jmp instructions
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ ec graph.box3 magenta
|
|||
ec graph.box4 rgb:000000
|
||||
ec graph.true green
|
||||
ec graph.false red
|
||||
ec graph.trufae blue
|
||||
ec graph.ujump blue
|
||||
ec graph.current blue
|
||||
ec graph.traced yellow
|
||||
ec gui.cflow yellow
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ ec graph.box3 rgb:aaa
|
|||
ec graph.box4 rgb:aaa
|
||||
ec graph.true rgb:aaa
|
||||
ec graph.false rgb:d52
|
||||
ec graph.trufae rgb:aaa
|
||||
ec graph.ujump rgb:aaa
|
||||
ec graph.current blue
|
||||
ec graph.traced red
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static struct {
|
|||
{ "graph.box4", rz_offsetof(RzConsPrintablePalette, graph_box4), rz_offsetof(RzConsPalette, graph_box4) },
|
||||
{ "graph.true", rz_offsetof(RzConsPrintablePalette, graph_true), rz_offsetof(RzConsPalette, graph_true) },
|
||||
{ "graph.false", rz_offsetof(RzConsPrintablePalette, graph_false), rz_offsetof(RzConsPalette, graph_false) },
|
||||
{ "graph.trufae", rz_offsetof(RzConsPrintablePalette, graph_trufae), rz_offsetof(RzConsPalette, graph_trufae) },
|
||||
{ "graph.ujump", rz_offsetof(RzConsPrintablePalette, graph_ujump), rz_offsetof(RzConsPalette, graph_ujump) },
|
||||
{ "graph.current", rz_offsetof(RzConsPrintablePalette, graph_current), rz_offsetof(RzConsPalette, graph_current) },
|
||||
{ "graph.traced", rz_offsetof(RzConsPrintablePalette, graph_traced), rz_offsetof(RzConsPalette, graph_traced) },
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ RZ_API void rz_cons_pal_init(RzConsContext *ctx) {
|
|||
ctx->cpal.graph_box4 = (RzColor)RzColor_GRAY;
|
||||
ctx->cpal.graph_true = (RzColor)RzColor_GREEN;
|
||||
ctx->cpal.graph_false = (RzColor)RzColor_RED;
|
||||
ctx->cpal.graph_trufae = (RzColor)RzColor_BLUE; // single jump
|
||||
ctx->cpal.graph_ujump = (RzColor)RzColor_BLUE; // single jump
|
||||
ctx->cpal.graph_traced = (RzColor)RzColor_YELLOW;
|
||||
ctx->cpal.graph_current = (RzColor)RzColor_BLUE;
|
||||
ctx->cpal.graph_diff_unknown = (RzColor)RzColor_MAGENTA;
|
||||
|
|
|
|||
|
|
@ -2060,7 +2060,7 @@ static int core_analysis_graph_construct_edges(RzCore *core, RzAnalysisFunction
|
|||
int is_html = rz_cons_singleton()->is_html;
|
||||
char *pal_jump = palColorFor("graph.true");
|
||||
char *pal_fail = palColorFor("graph.false");
|
||||
char *pal_trfa = palColorFor("graph.trufae");
|
||||
char *pal_trfa = palColorFor("graph.ujump");
|
||||
int nodes = 0;
|
||||
rz_list_foreach (fcn->bbs, iter, bbi) {
|
||||
if (bbi->jump != UT64_MAX) {
|
||||
|
|
@ -2429,7 +2429,7 @@ static int core_analysis_graph_nodes(RzCore *core, RzAnalysisFunction *fcn, int
|
|||
Sdb *DB = NULL;
|
||||
char *pal_jump = palColorFor("graph.true");
|
||||
char *pal_fail = palColorFor("graph.false");
|
||||
char *pal_trfa = palColorFor("graph.trufae");
|
||||
char *pal_trfa = palColorFor("graph.ujump");
|
||||
char *pal_curr = palColorFor("graph.current");
|
||||
char *pal_traced = palColorFor("graph.traced");
|
||||
char *pal_box4 = palColorFor("graph.box4");
|
||||
|
|
@ -4217,7 +4217,7 @@ RZ_API RzList *rz_core_analysis_graph_to(RzCore *core, ut64 addr, int n) {
|
|||
return paths;
|
||||
}
|
||||
|
||||
RZ_API int rz_core_analysis_graph(RzCore *core, ut64 addr, int opts) {
|
||||
RZ_API bool rz_core_analysis_graph(RzCore *core, ut64 addr, int opts) {
|
||||
ut64 from = rz_config_get_i(core->config, "graph.from");
|
||||
ut64 to = rz_config_get_i(core->config, "graph.to");
|
||||
const char *font = rz_config_get(core->config, "graph.font");
|
||||
|
|
|
|||
|
|
@ -7510,19 +7510,19 @@ static void cmd_analysis_graph(RzCore *core, const char *input) {
|
|||
switch (input[1]) {
|
||||
case 'j': { // "agdj"
|
||||
ut64 addr = input[2] ? rz_num_math(core->num, input + 2) : core->offset;
|
||||
rz_core_gdiff_fcn(core, addr, core->offset);
|
||||
rz_core_gdiff_function_1_file(core, addr, core->offset);
|
||||
rz_core_analysis_graph(core, addr, diff_opt | RZ_CORE_ANALYSIS_JSON);
|
||||
break;
|
||||
}
|
||||
case 'J': { // "agdJ"
|
||||
ut64 addr = input[2] ? rz_num_math(core->num, input + 2) : core->offset;
|
||||
rz_core_gdiff_fcn(core, addr, core->offset);
|
||||
rz_core_gdiff_function_1_file(core, addr, core->offset);
|
||||
rz_core_analysis_graph(core, addr, diff_opt | RZ_CORE_ANALYSIS_JSON | RZ_CORE_ANALYSIS_JSON_FORMAT_DISASM);
|
||||
break;
|
||||
}
|
||||
case '*': { // "agd*"
|
||||
ut64 addr = input[2] ? rz_num_math(core->num, input + 2) : core->offset;
|
||||
rz_core_gdiff_fcn(core, addr, core->offset);
|
||||
rz_core_gdiff_function_1_file(core, addr, core->offset);
|
||||
rz_core_analysis_graph(core, addr, diff_opt | RZ_CORE_ANALYSIS_STAR);
|
||||
break;
|
||||
}
|
||||
|
|
@ -7539,7 +7539,7 @@ static void cmd_analysis_graph(RzCore *core, const char *input) {
|
|||
}
|
||||
case 'd': { // "agdd"
|
||||
ut64 addr = input[2] ? rz_num_math(core->num, input + 2) : core->offset;
|
||||
rz_core_gdiff_fcn(core, addr, core->offset);
|
||||
rz_core_gdiff_function_1_file(core, addr, core->offset);
|
||||
rz_core_analysis_graph(core, addr, diff_opt);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -765,7 +765,7 @@ RZ_IPI int rz_cmd_cmp(void *data, const char *input) {
|
|||
case 'f': // "cgf"
|
||||
eprintf("TODO: agf is experimental\n");
|
||||
rz_analysis_diff_setup(core->analysis, true, -1, -1);
|
||||
rz_core_gdiff_fcn(core, core->offset,
|
||||
rz_core_gdiff_function_1_file(core, core->offset,
|
||||
rz_num_math(core->num, input + 2));
|
||||
return false;
|
||||
case ' ':
|
||||
|
|
@ -809,8 +809,8 @@ RZ_IPI int rz_cmd_cmp(void *data, const char *input) {
|
|||
|
||||
rz_core_bin_load(core2, file2,
|
||||
rz_config_get_i(core->config, "bin.baddr"));
|
||||
rz_core_gdiff(core, core2);
|
||||
rz_core_diff_show(core, core2);
|
||||
rz_core_gdiff_2_files(core, core2);
|
||||
rz_core_diff_show(core, core2, false);
|
||||
/* exchange a segfault with a memleak */
|
||||
core2->config = NULL;
|
||||
rz_core_free(core2);
|
||||
|
|
|
|||
|
|
@ -3467,7 +3467,7 @@ static bool cmd_print_blocks(RzCore *core, const char *input) {
|
|||
if (use_color) {
|
||||
if (s) {
|
||||
if (s->perm & RZ_PERM_X) {
|
||||
rz_cons_print(rz_cons_singleton()->context->pal.graph_trufae);
|
||||
rz_cons_print(rz_cons_singleton()->context->pal.graph_ujump);
|
||||
} else {
|
||||
rz_cons_print(rz_cons_singleton()->context->pal.graph_true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1615,7 +1615,7 @@ RZ_API void rz_core_autocomplete(RZ_NULLABLE RzCore *core, RzLineCompletion *com
|
|||
ADDARG("graph.box4")
|
||||
ADDARG("graph.true")
|
||||
ADDARG("graph.false")
|
||||
ADDARG("graph.trufae")
|
||||
ADDARG("graph.ujump")
|
||||
ADDARG("graph.current")
|
||||
ADDARG("graph.traced")
|
||||
ADDARG("gui.cflow")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@
|
|||
#include <rz_util.h>
|
||||
#include <rz_core.h>
|
||||
|
||||
RZ_API int rz_core_gdiff_fcn(RzCore *c, ut64 addr, ut64 addr2) {
|
||||
/**
|
||||
* \brief Calculates basic block differences of 2 functions within the same file
|
||||
*
|
||||
* Calculates basic block differences of 2 functions within the same file
|
||||
* */
|
||||
RZ_API bool rz_core_gdiff_function_1_file(RzCore *c, ut64 addr, ut64 addr2) {
|
||||
RzList *la, *lb;
|
||||
RzAnalysisFunction *fa = rz_analysis_get_function_at(c->analysis, addr);
|
||||
RzAnalysisFunction *fb = rz_analysis_get_function_at(c->analysis, addr2);
|
||||
|
|
@ -34,8 +39,55 @@ RZ_API int rz_core_gdiff_fcn(RzCore *c, ut64 addr, ut64 addr2) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Fingerprint functions and blocks, then diff. */
|
||||
RZ_API int rz_core_gdiff(RzCore *c, RzCore *c2) {
|
||||
/**
|
||||
* \brief Calculates basic block differences of 2 functions within 2 files
|
||||
*
|
||||
* Calculates basic block differences of 2 functions within 2 files
|
||||
* */
|
||||
RZ_API bool rz_core_gdiff_function_2_files(RzCore *c, RzCore *c2, ut64 addr, ut64 addr2) {
|
||||
rz_return_val_if_fail(c && c2, false);
|
||||
RzList *la, *lb;
|
||||
RzAnalysisFunction *fa = rz_analysis_get_function_at(c->analysis, addr);
|
||||
RzAnalysisFunction *fb = rz_analysis_get_function_at(c2->analysis, addr2);
|
||||
if (!fa || !fb) {
|
||||
eprintf("cannot get functions at 0x%" PFMT64x " or at 0x%" PFMT64x "\n", addr, addr2);
|
||||
return false;
|
||||
}
|
||||
RzAnalysisBlock *bb;
|
||||
RzListIter *iter;
|
||||
rz_list_foreach (fa->bbs, iter, bb) {
|
||||
if (rz_analysis_diff_fingerprint_bb(c->analysis, bb) < 0) {
|
||||
eprintf("cannot fingerprint 0x%" PFMT64x "\n", addr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
rz_list_foreach (fb->bbs, iter, bb) {
|
||||
if (rz_analysis_diff_fingerprint_bb(c2->analysis, bb) < 0) {
|
||||
eprintf("cannot fingerprint 0x%" PFMT64x "\n", addr2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rz_analysis_diff_fingerprint_fcn(c->analysis, fa);
|
||||
rz_analysis_diff_fingerprint_fcn(c2->analysis, fb);
|
||||
|
||||
la = rz_list_new();
|
||||
rz_list_append(la, fa);
|
||||
lb = rz_list_new();
|
||||
rz_list_append(lb, fb);
|
||||
rz_analysis_diff_fcn(c->analysis, la, lb);
|
||||
rz_list_free(la);
|
||||
rz_list_free(lb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Calculates basic block differences of all functions within 2 files
|
||||
*
|
||||
* Calculates basic block differences of all functions within 2 files.
|
||||
* */
|
||||
RZ_API bool rz_core_gdiff_2_files(RzCore *c, RzCore *c2) {
|
||||
rz_return_val_if_fail(c && c2, false);
|
||||
RzCore *cores[2] = { c, c2 };
|
||||
RzAnalysisFunction *fcn;
|
||||
RzAnalysisBlock *bb;
|
||||
|
|
@ -69,45 +121,76 @@ RZ_API int rz_core_gdiff(RzCore *c, RzCore *c2) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* copypasta from rz_diff */
|
||||
static void diffrow(ut64 addr, const char *name, ut32 size, int maxnamelen,
|
||||
int digits, ut64 addr2, const char *name2, ut32 size2,
|
||||
const char *match, double dist, int bare) {
|
||||
double dist, bool is_new, bool bare, bool color) {
|
||||
|
||||
const char *type = NULL;
|
||||
const char *prefix = NULL;
|
||||
const char *suffix = color ? Color_RESET : "";
|
||||
|
||||
if (dist == 1.0) {
|
||||
prefix = color ? Color_BGREEN : "";
|
||||
type = color ? Color_BGREEN "MATCH " Color_RESET : "MATCH ";
|
||||
} else if (dist >= 0.5) {
|
||||
prefix = color ? Color_BYELLOW : "";
|
||||
type = color ? Color_BYELLOW "SIMILAR" Color_RESET : "SIMILAR";
|
||||
} else if (is_new) {
|
||||
dist = 0.0;
|
||||
prefix = color ? Color_BBLUE : "";
|
||||
type = color ? Color_BBLUE "NEW " Color_RESET : "NEW ";
|
||||
} else {
|
||||
prefix = color ? Color_BRED : "";
|
||||
type = color ? Color_BRED "UNMATCH" Color_RESET : "UNMATCH";
|
||||
}
|
||||
|
||||
if (bare) {
|
||||
if (addr2 == UT64_MAX || !name2) {
|
||||
printf("0x%016" PFMT64x " |%8s (%f)\n", addr, match, dist);
|
||||
printf("0x%016" PFMT64x " | %7s (%s%f%s)\n", addr, type, prefix, dist, suffix);
|
||||
} else {
|
||||
printf("0x%016" PFMT64x " |%8s (%f) | 0x%016" PFMT64x "\n", addr, match, dist, addr2);
|
||||
printf("0x%016" PFMT64x " | %7s (%s%f%s) | 0x%016" PFMT64x "\n", addr, type, prefix, dist, suffix, addr2);
|
||||
}
|
||||
} else {
|
||||
if (addr2 == UT64_MAX || !name2) {
|
||||
printf("%*s %*d 0x%" PFMT64x " |%8s (%f)\n",
|
||||
maxnamelen, name, digits, size, addr, match, dist);
|
||||
printf("%*s %*d 0x%016" PFMT64x " | %7s (%s%f%s)\n",
|
||||
maxnamelen, name, digits, size, addr, type, prefix, dist, suffix);
|
||||
} else {
|
||||
printf("%*s %*d 0x%" PFMT64x " |%8s (%f) | 0x%" PFMT64x " %*d %s\n",
|
||||
maxnamelen, name, digits, size, addr, match, dist, addr2,
|
||||
printf("%*s %*d 0x%016" PFMT64x " | %7s (%s%f%s) | 0x%016" PFMT64x " %*d %s\n",
|
||||
maxnamelen, name, digits, size, addr, type, prefix, dist, suffix, addr2,
|
||||
digits, size2, name2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RZ_API void rz_core_diff_show(RzCore *c, RzCore *c2) {
|
||||
bool bare = rz_config_get_i(c->config, "diff.bare") || rz_config_get_i(c2->config, "diff.bare");
|
||||
RZ_API void rz_core_diff_show(RzCore *c, RzCore *c2, bool json) {
|
||||
rz_return_if_fail(c && c2);
|
||||
bool color = rz_config_get_i(c->config, "scr.color") > 0 || rz_config_get_i(c2->config, "scr.color") > 0;
|
||||
bool bare = rz_config_get_b(c->config, "diff.bare") || rz_config_get_b(c2->config, "diff.bare");
|
||||
bool is_new = false;
|
||||
RzList *fcns = rz_analysis_get_fcns(c->analysis);
|
||||
const char *match;
|
||||
RzListIter *iter;
|
||||
RzAnalysisFunction *f;
|
||||
int maxnamelen = 0;
|
||||
ut64 maxsize = 0;
|
||||
int digits = 1;
|
||||
int len;
|
||||
PJ *pj = NULL;
|
||||
|
||||
if (json) {
|
||||
pj = pj_new();
|
||||
if (!pj) {
|
||||
eprintf("cannot alocate json\n");
|
||||
return;
|
||||
}
|
||||
pj_a(pj);
|
||||
}
|
||||
|
||||
rz_list_foreach (fcns, iter, f) {
|
||||
if (f->name && (len = strlen(f->name)) > maxnamelen) {
|
||||
maxnamelen = len;
|
||||
}
|
||||
if (rz_analysis_function_linear_size(f) > maxsize) {
|
||||
maxsize = rz_analysis_function_linear_size(f);
|
||||
if (rz_analysis_function_realsize(f) > maxsize) {
|
||||
maxsize = rz_analysis_function_realsize(f);
|
||||
}
|
||||
}
|
||||
fcns = rz_analysis_get_fcns(c2->analysis);
|
||||
|
|
@ -115,8 +198,8 @@ RZ_API void rz_core_diff_show(RzCore *c, RzCore *c2) {
|
|||
if (f->name && (len = strlen(f->name)) > maxnamelen) {
|
||||
maxnamelen = len;
|
||||
}
|
||||
if (rz_analysis_function_linear_size(f) > maxsize) {
|
||||
maxsize = rz_analysis_function_linear_size(f);
|
||||
if (rz_analysis_function_realsize(f) > maxsize) {
|
||||
maxsize = rz_analysis_function_realsize(f);
|
||||
}
|
||||
}
|
||||
while (maxsize > 9) {
|
||||
|
|
@ -126,7 +209,7 @@ RZ_API void rz_core_diff_show(RzCore *c, RzCore *c2) {
|
|||
|
||||
fcns = rz_analysis_get_fcns(c->analysis);
|
||||
if (rz_list_empty(fcns)) {
|
||||
eprintf("No functions found, try running with -A or load a project\n");
|
||||
eprintf("functions list is empty. analyze the binary first\n");
|
||||
return;
|
||||
}
|
||||
rz_list_sort(fcns, c->analysis->columnSort);
|
||||
|
|
@ -137,18 +220,37 @@ RZ_API void rz_core_diff_show(RzCore *c, RzCore *c2) {
|
|||
case RZ_ANALYSIS_FCN_TYPE_SYM:
|
||||
switch (f->diff->type) {
|
||||
case RZ_ANALYSIS_DIFF_TYPE_MATCH:
|
||||
match = "MATCH";
|
||||
break;
|
||||
case RZ_ANALYSIS_DIFF_TYPE_UNMATCH:
|
||||
match = "UNMATCH";
|
||||
is_new = false;
|
||||
break;
|
||||
default:
|
||||
match = "NEW";
|
||||
f->diff->dist = 0;
|
||||
is_new = true;
|
||||
}
|
||||
if (json) {
|
||||
double dist = f->diff->dist;
|
||||
pj_o(pj);
|
||||
pj_kd(pj, "distance", f->diff->dist);
|
||||
pj_ks(pj, "type", dist >= 1.0 ? "MATCH" : (dist >= 0.5 ? "SIMILAR" : (is_new ? "NEW" : "UNMATCH")));
|
||||
if (f->name) {
|
||||
pj_ko(pj, "original");
|
||||
pj_ks(pj, "name", f->name);
|
||||
pj_kn(pj, "addr", f->addr);
|
||||
pj_kn(pj, "size", rz_analysis_function_realsize(f));
|
||||
pj_end(pj);
|
||||
}
|
||||
if (f->diff->name) {
|
||||
pj_ko(pj, "modified");
|
||||
pj_ks(pj, "name", f->diff->name);
|
||||
pj_kn(pj, "addr", f->diff->addr);
|
||||
pj_kn(pj, "size", f->diff->size);
|
||||
pj_end(pj);
|
||||
}
|
||||
pj_end(pj);
|
||||
} else {
|
||||
diffrow(f->addr, f->name, rz_analysis_function_realsize(f), maxnamelen, digits,
|
||||
f->diff->addr, f->diff->name, f->diff->size,
|
||||
f->diff->dist, is_new, bare, color);
|
||||
}
|
||||
diffrow(f->addr, f->name, rz_analysis_function_linear_size(f), maxnamelen, digits,
|
||||
f->diff->addr, f->diff->name, f->diff->size,
|
||||
match, f->diff->dist, bare);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -159,11 +261,320 @@ RZ_API void rz_core_diff_show(RzCore *c, RzCore *c2) {
|
|||
case RZ_ANALYSIS_FCN_TYPE_FCN:
|
||||
case RZ_ANALYSIS_FCN_TYPE_SYM:
|
||||
if (f->diff->type == RZ_ANALYSIS_DIFF_TYPE_NULL) {
|
||||
diffrow(f->addr, f->name, rz_analysis_function_linear_size(f), maxnamelen,
|
||||
digits, f->diff->addr, f->diff->name, f->diff->size,
|
||||
"NEW", 0, bare); //f->diff->dist, bare);
|
||||
if (json) {
|
||||
pj_o(pj);
|
||||
pj_kd(pj, "distance", 0.0);
|
||||
pj_ks(pj, "type", "NEW");
|
||||
if (f->name) {
|
||||
pj_ko(pj, "original");
|
||||
pj_ks(pj, "name", f->name);
|
||||
pj_kn(pj, "addr", f->addr);
|
||||
pj_kn(pj, "size", rz_analysis_function_realsize(f));
|
||||
pj_end(pj);
|
||||
}
|
||||
if (f->diff->name) {
|
||||
pj_ko(pj, "modified");
|
||||
pj_ks(pj, "name", f->diff->name);
|
||||
pj_kn(pj, "addr", f->diff->addr);
|
||||
pj_kn(pj, "size", f->diff->size);
|
||||
pj_end(pj);
|
||||
}
|
||||
pj_end(pj);
|
||||
} else {
|
||||
diffrow(f->addr, f->name, rz_analysis_function_realsize(f), maxnamelen,
|
||||
digits, f->diff->addr, f->diff->name, f->diff->size,
|
||||
0.0, true, bare, color);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (json) {
|
||||
pj_end(pj);
|
||||
printf("%s\n", pj_string(pj));
|
||||
pj_free(pj);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *diff_color(RzAnalysisBlock *bbi) {
|
||||
if (!bbi->diff) {
|
||||
return "white";
|
||||
}
|
||||
|
||||
switch (bbi->diff->type) {
|
||||
case RZ_ANALYSIS_DIFF_TYPE_MATCH:
|
||||
return "lightgray";
|
||||
case RZ_ANALYSIS_DIFF_TYPE_UNMATCH:
|
||||
return bbi->diff->dist >= 0.5 ? "yellow" : "red";
|
||||
default:
|
||||
return "turquoise";
|
||||
}
|
||||
}
|
||||
|
||||
static void print_color_node(RzCore *core, RzAnalysisBlock *bbi) {
|
||||
bool color_current = rz_config_get_i(core->config, "graph.gv.current");
|
||||
bool current = rz_analysis_block_contains(bbi, core->offset);
|
||||
if (current && color_current) {
|
||||
printf("\t\"0x%08" PFMT64x "\" ", bbi->addr);
|
||||
printf("\t[fillcolor=gray style=filled shape=box];\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int graph_construct_nodes(RzCore *core, RzCore *core2, RzAnalysisFunction *fcn, PJ *pj) {
|
||||
char addr_a[32], addr_b[32];
|
||||
|
||||
RzAnalysisBlock *bbi;
|
||||
RzListIter *iter;
|
||||
int is_json = pj != NULL;
|
||||
const char *font = rz_config_get(core->config, "graph.font");
|
||||
int nodes = 0;
|
||||
|
||||
snprintf(addr_a, sizeof(addr_a), "0x%08" PFMT64x, fcn->addr);
|
||||
snprintf(addr_b, sizeof(addr_b), "0x%08" PFMT64x, fcn->diff->addr);
|
||||
|
||||
const char *norig = fcn->name ? fcn->name : addr_a;
|
||||
const char *nmodi = fcn->diff->name ? fcn->diff->name : addr_b;
|
||||
|
||||
rz_list_foreach (fcn->bbs, iter, bbi) {
|
||||
if (is_json) {
|
||||
RzDebugTracepoint *t = rz_debug_trace_get(core->dbg, bbi->addr);
|
||||
ut8 *buf = malloc(bbi->size);
|
||||
pj_o(pj);
|
||||
pj_kn(pj, "offset", bbi->addr);
|
||||
pj_kn(pj, "size", bbi->size);
|
||||
if (bbi->jump != UT64_MAX) {
|
||||
pj_kn(pj, "jump", bbi->jump);
|
||||
}
|
||||
if (bbi->fail != -1) {
|
||||
pj_kn(pj, "fail", bbi->fail);
|
||||
}
|
||||
if (bbi->switch_op) {
|
||||
RzAnalysisSwitchOp *op = bbi->switch_op;
|
||||
pj_k(pj, "switchop");
|
||||
pj_o(pj);
|
||||
pj_kn(pj, "offset", op->addr);
|
||||
pj_kn(pj, "defval", op->def_val);
|
||||
pj_kn(pj, "maxval", op->max_val);
|
||||
pj_kn(pj, "minval", op->min_val);
|
||||
pj_k(pj, "cases");
|
||||
pj_a(pj);
|
||||
RzAnalysisCaseOp *case_op;
|
||||
RzListIter *case_iter;
|
||||
rz_list_foreach (op->cases, case_iter, case_op) {
|
||||
pj_o(pj);
|
||||
pj_kn(pj, "offset", case_op->addr);
|
||||
pj_kn(pj, "value", case_op->value);
|
||||
pj_kn(pj, "jump", case_op->jump);
|
||||
pj_end(pj);
|
||||
}
|
||||
pj_end(pj);
|
||||
pj_end(pj);
|
||||
}
|
||||
if (t) {
|
||||
pj_k(pj, "trace");
|
||||
pj_o(pj);
|
||||
pj_ki(pj, "count", t->count);
|
||||
pj_ki(pj, "times", t->times);
|
||||
pj_end(pj);
|
||||
}
|
||||
pj_kn(pj, "colorize", bbi->colorize);
|
||||
pj_k(pj, "ops");
|
||||
pj_a(pj);
|
||||
if (buf) {
|
||||
rz_io_read_at(core->io, bbi->addr, buf, bbi->size);
|
||||
rz_core_print_disasm_json(core, bbi->addr, buf, bbi->size, 0, pj);
|
||||
free(buf);
|
||||
} else {
|
||||
eprintf("cannot allocate %" PFMT64u " byte(s)\n", bbi->size);
|
||||
}
|
||||
pj_end(pj);
|
||||
pj_end(pj);
|
||||
continue;
|
||||
} else {
|
||||
const char *fillcolor = diff_color(bbi);
|
||||
nodes++;
|
||||
RzConfigHold *hc = rz_config_hold_new(core->config);
|
||||
rz_config_hold_i(hc, "scr.color", "scr.utf8", "asm.offset", "asm.lines",
|
||||
"asm.cmt.right", "asm.lines.fcn", "asm.bytes", "asm.comments", NULL);
|
||||
rz_config_set_i(core->config, "scr.utf8", 0);
|
||||
rz_config_set_i(core->config, "asm.offset", 0);
|
||||
rz_config_set_i(core->config, "asm.lines", 0);
|
||||
rz_config_set_i(core->config, "asm.cmt.right", 0);
|
||||
rz_config_set_i(core->config, "asm.lines.fcn", 0);
|
||||
rz_config_set_i(core->config, "asm.bytes", 0);
|
||||
rz_config_set_i(core->config, "asm.comments", 0);
|
||||
rz_config_set_i(core->config, "scr.color", COLOR_MODE_DISABLED);
|
||||
|
||||
char *original = rz_core_cmd_strf(core, "pdb @ 0x%08" PFMT64x, bbi->addr);
|
||||
|
||||
if (bbi->diff && bbi->diff->type == RZ_ANALYSIS_DIFF_TYPE_UNMATCH) {
|
||||
RzConfig *oc = core2->config;
|
||||
core2->config = core->config;
|
||||
|
||||
char *modified = rz_core_cmd_strf(core2, "pdb @ 0x%08" PFMT64x, bbi->diff->addr);
|
||||
|
||||
RzDiff *dff = rz_diff_lines_new(original, modified, NULL);
|
||||
char *diffstr = rz_diff_unified_text(dff, norig, nmodi, false, false);
|
||||
rz_diff_free(dff);
|
||||
|
||||
rz_str_replace_char(diffstr, '"', '\'');
|
||||
diffstr = rz_str_replace(diffstr, "\n", "\\l", 1);
|
||||
printf("\t\"0x%08" PFMT64x "\" [fillcolor=\"%s\","
|
||||
"color=\"black\", fontname=\"%s\","
|
||||
" label=\"%s\", URL=\"%s/0x%08" PFMT64x "\"]\n",
|
||||
bbi->addr, fillcolor, font, diffstr, fcn->name,
|
||||
bbi->addr);
|
||||
free(diffstr);
|
||||
free(modified);
|
||||
core2->config = oc;
|
||||
} else {
|
||||
rz_str_replace_char(original, '"', '\'');
|
||||
original = rz_str_replace(original, "\n", "\\l", 1);
|
||||
printf("\t\"0x%08" PFMT64x "\" [fillcolor=\"%s\","
|
||||
"color=\"black\", fontname=\"%s\","
|
||||
" label=\"%s\", URL=\"%s/0x%08" PFMT64x "\"]\n",
|
||||
bbi->addr, fillcolor, font, original, fcn->name, bbi->addr);
|
||||
}
|
||||
free(original);
|
||||
rz_config_set_i(core->config, "scr.color", 1);
|
||||
rz_config_hold_restore(hc);
|
||||
rz_config_hold_free(hc);
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
static int graph_construct_edges(RzCore *core, RzAnalysisFunction *fcn) {
|
||||
RzAnalysisBlock *bbi;
|
||||
RzListIter *iter;
|
||||
const char *pal_jump = "#0037da";
|
||||
const char *pal_fail = "#c50f1f";
|
||||
const char *pal_true = "#13a10e";
|
||||
int nodes = 0;
|
||||
rz_list_foreach (fcn->bbs, iter, bbi) {
|
||||
if (bbi->jump != UT64_MAX) {
|
||||
nodes++;
|
||||
printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color=\"%s\"];\n",
|
||||
bbi->addr, bbi->jump,
|
||||
bbi->fail != UT64_MAX ? pal_true : pal_jump);
|
||||
print_color_node(core, bbi);
|
||||
}
|
||||
if (bbi->fail != UT64_MAX) {
|
||||
nodes++;
|
||||
printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color=\"%s\"];\n",
|
||||
bbi->addr, bbi->fail, pal_fail);
|
||||
print_color_node(core, bbi);
|
||||
}
|
||||
if (bbi->switch_op) {
|
||||
RzAnalysisCaseOp *caseop;
|
||||
RzListIter *iter;
|
||||
|
||||
if (bbi->fail != UT64_MAX) {
|
||||
printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color=\"%s\"];\n",
|
||||
bbi->addr, bbi->fail, pal_fail);
|
||||
print_color_node(core, bbi);
|
||||
}
|
||||
rz_list_foreach (bbi->switch_op->cases, iter, caseop) {
|
||||
nodes++;
|
||||
printf("\t\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x "\" [color2=\"%s\"];\n",
|
||||
caseop->addr, caseop->jump, pal_fail);
|
||||
print_color_node(core, bbi);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
static int draw_graph_nodes(RzCore *core, RzCore *core2, RzAnalysisFunction *fcn, PJ *pj) {
|
||||
rz_return_val_if_fail(fcn && fcn->bbs, -1);
|
||||
int nodes = 0;
|
||||
|
||||
if (pj) {
|
||||
char *fcn_name_escaped = rz_str_escape_utf8_for_json(fcn->name, -1);
|
||||
pj_o(pj);
|
||||
pj_ks(pj, "name", rz_str_get_null(fcn_name_escaped));
|
||||
free(fcn_name_escaped);
|
||||
pj_kn(pj, "offset", fcn->addr);
|
||||
pj_ki(pj, "ninstr", fcn->ninstr);
|
||||
pj_ki(pj, "nargs",
|
||||
rz_analysis_var_count(core->analysis, fcn, 'r', 1) +
|
||||
rz_analysis_var_count(core->analysis, fcn, 's', 1) +
|
||||
rz_analysis_var_count(core->analysis, fcn, 'b', 1));
|
||||
pj_ki(pj, "nlocals",
|
||||
rz_analysis_var_count(core->analysis, fcn, 'r', 0) +
|
||||
rz_analysis_var_count(core->analysis, fcn, 's', 0) +
|
||||
rz_analysis_var_count(core->analysis, fcn, 'b', 0));
|
||||
pj_kn(pj, "size", rz_analysis_function_linear_size(fcn));
|
||||
pj_ki(pj, "stack", fcn->maxstack);
|
||||
pj_ks(pj, "type", rz_analysis_fcntype_tostring(fcn->type));
|
||||
pj_k(pj, "blocks");
|
||||
pj_a(pj);
|
||||
}
|
||||
nodes += graph_construct_nodes(core, core2, fcn, pj);
|
||||
if (!pj) {
|
||||
nodes += graph_construct_edges(core, fcn);
|
||||
}
|
||||
if (pj) {
|
||||
pj_end(pj);
|
||||
pj_end(pj);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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.
|
||||
* */
|
||||
RZ_API bool rz_core_diff_show_function(RzCore *core, RzCore *core2, ut64 addr1, bool json) {
|
||||
rz_return_val_if_fail(core && core2, false);
|
||||
const char *font = rz_config_get(core->config, "graph.font");
|
||||
|
||||
int nodes = 0;
|
||||
PJ *pj = NULL;
|
||||
RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr1);
|
||||
if (!fcn) {
|
||||
eprintf("cannot get functions at 0x%" PFMT64x "\n", addr1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!json) {
|
||||
const char *gv_edge = rz_config_get(core->config, "graph.gv.edge");
|
||||
const char *gv_node = rz_config_get(core->config, "graph.gv.node");
|
||||
const char *gv_spline = rz_config_get(core->config, "graph.gv.spline");
|
||||
if (!gv_edge || !*gv_edge) {
|
||||
gv_edge = "arrowhead=\"normal\"";
|
||||
}
|
||||
if (!gv_node || !*gv_node) {
|
||||
gv_node = "fillcolor=gray style=filled shape=box";
|
||||
}
|
||||
if (!gv_spline || !*gv_spline) {
|
||||
gv_spline = "splines=\"ortho\"";
|
||||
}
|
||||
printf("digraph code {\n"
|
||||
"\tgraph [bgcolor=azure fontsize=8 fontname=\"%s\" %s];\n"
|
||||
"\tnode [%s];\n"
|
||||
"\tedge [%s];\n",
|
||||
font, gv_spline, gv_node, gv_edge);
|
||||
} else {
|
||||
pj = pj_new();
|
||||
if (!pj) {
|
||||
return false;
|
||||
}
|
||||
pj_a(pj);
|
||||
}
|
||||
nodes += draw_graph_nodes(core, core2, fcn, pj);
|
||||
if (nodes < 1 && !json) {
|
||||
printf("\t\"0x%08" PFMT64x "\";\n", addr1);
|
||||
}
|
||||
if (json) {
|
||||
pj_end(pj);
|
||||
printf("%s\n", pj_string(pj));
|
||||
pj_free(pj);
|
||||
} else {
|
||||
printf("}\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ static inline void diff_unified_append_data(RzDiff *diff, const void *array, st3
|
|||
rz_strbuf_appendf(sb, "%s%c", bcol, prefix);
|
||||
for (st32 i = beg; i < end; ++i) {
|
||||
if (newline || (is_bytes && count > 0 && !FAST_MOD64(count))) {
|
||||
rz_strbuf_appendf(sb, "%s\n%s%c", bcol, ecol, prefix);
|
||||
rz_strbuf_appendf(sb, "%s\n%s%c", ecol, bcol, prefix);
|
||||
newline = false;
|
||||
}
|
||||
rz_strbuf_init(&tmp);
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ typedef struct rz_cons_palette_t {
|
|||
RzColor graph_box4;
|
||||
RzColor graph_true;
|
||||
RzColor graph_false;
|
||||
RzColor graph_trufae;
|
||||
RzColor graph_ujump;
|
||||
RzColor graph_traced;
|
||||
RzColor graph_current;
|
||||
RzColor graph_diff_match;
|
||||
|
|
@ -343,7 +343,7 @@ typedef struct rz_cons_printable_palette_t {
|
|||
char *graph_diff_new;
|
||||
char *graph_true;
|
||||
char *graph_false;
|
||||
char *graph_trufae;
|
||||
char *graph_ujump;
|
||||
char *graph_traced;
|
||||
char *graph_current;
|
||||
char **rainbow; // rainbow
|
||||
|
|
|
|||
|
|
@ -669,7 +669,7 @@ RZ_API ut64 rz_core_analysis_fcn_list_size(RzCore *core);
|
|||
RZ_API int rz_core_analysis_fcn_clean(RzCore *core, ut64 addr);
|
||||
RZ_API int rz_core_print_bb_custom(RzCore *core, RzAnalysisFunction *fcn);
|
||||
RZ_API int rz_core_print_bb_gml(RzCore *core, RzAnalysisFunction *fcn);
|
||||
RZ_API int rz_core_analysis_graph(RzCore *core, ut64 addr, int opts);
|
||||
RZ_API bool rz_core_analysis_graph(RzCore *core, ut64 addr, int opts);
|
||||
RZ_API RzList *rz_core_analysis_graph_to(RzCore *core, ut64 addr, int n);
|
||||
RZ_API int rz_core_analysis_all(RzCore *core);
|
||||
RZ_API bool rz_core_analysis_everything(RzCore *core, bool experimental, char *dh_orig);
|
||||
|
|
@ -763,8 +763,9 @@ RZ_API int rz_core_pseudo_code(RzCore *core, const char *input);
|
|||
|
||||
/* gdiff.c */
|
||||
RZ_API int rz_core_zdiff(RzCore *c, RzCore *c2);
|
||||
RZ_API int rz_core_gdiff(RzCore *core1, RzCore *core2);
|
||||
RZ_API int rz_core_gdiff_fcn(RzCore *c, ut64 addr, ut64 addr2);
|
||||
RZ_API bool rz_core_gdiff_2_files(RzCore *core1, RzCore *core2);
|
||||
RZ_API bool rz_core_gdiff_function_1_file(RzCore *c, ut64 addr, ut64 addr2);
|
||||
RZ_API bool rz_core_gdiff_function_2_files(RzCore *core1, RzCore *core2, ut64 addr, ut64 addr2);
|
||||
|
||||
RZ_API char *rz_core_sysenv_begin(RzCore *core, const char *cmd);
|
||||
RZ_API void rz_core_sysenv_end(RzCore *core, const char *cmd);
|
||||
|
|
@ -899,7 +900,8 @@ RZ_API RzList * /*<RzIOMap*>*/ rz_core_get_boundaries_prot(RzCore *core, int pro
|
|||
RZ_API void rz_core_hack_help(const RzCore *core);
|
||||
RZ_API int rz_core_hack(RzCore *core, const char *op);
|
||||
RZ_API bool rz_core_dump(RzCore *core, const char *file, ut64 addr, ut64 size, int append);
|
||||
RZ_API void rz_core_diff_show(RzCore *core, RzCore *core2);
|
||||
RZ_API void rz_core_diff_show(RzCore *core, RzCore *core2, bool json);
|
||||
RZ_API bool rz_core_diff_show_function(RzCore *core, RzCore *core2, ut64 addr, bool json);
|
||||
RZ_API void rz_core_clippy(RzCore *core, const char *msg);
|
||||
|
||||
/* watchers */
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ typedef enum {
|
|||
DIFF_TYPE_SECTIONS,
|
||||
DIFF_TYPE_STRINGS,
|
||||
DIFF_TYPE_SYMBOLS,
|
||||
DIFF_TYPE_PLOTDIFF,
|
||||
} DiffType;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -56,6 +57,7 @@ typedef enum {
|
|||
DIFF_OPT_VERSION,
|
||||
DIFF_OPT_DISTANCE,
|
||||
DIFF_OPT_UNIFIED,
|
||||
DIFF_OPT_GRAPH,
|
||||
} DiffOption;
|
||||
|
||||
typedef struct diff_context_t {
|
||||
|
|
@ -68,8 +70,8 @@ typedef struct diff_context_t {
|
|||
bool show_time;
|
||||
bool colors;
|
||||
const char *architecture;
|
||||
const char *command_a;
|
||||
const char *command_b;
|
||||
const char *input_a;
|
||||
const char *input_b;
|
||||
const char *file_a;
|
||||
const char *file_b;
|
||||
} DiffContext;
|
||||
|
|
@ -162,9 +164,9 @@ static void rz_diff_show_help(bool usage_only) {
|
|||
" -A compare virtual and physical addresses\n"
|
||||
" -C show colors\n"
|
||||
" -T show timestamp information\n"
|
||||
" -0 [cmd] command to execute for file0 when option -t 'commands' is given.\n"
|
||||
" if -1 is not set, it will execute the same cmd for file1.\n"
|
||||
" -1 [cmd] command to execute for file1 when option -t 'commands' is given.\n"
|
||||
" -0 [cmd] input for file0 when option -t 'commands' is given.\n"
|
||||
" the same value will be set for file1, if -1 is not set.\n"
|
||||
" -1 [cmd] input for file1 when option -t 'commands' is given.\n"
|
||||
" -t [type] compute the difference between two files based on its type:\n"
|
||||
" bytes | compares raw bytes in the files (only for small files)\n"
|
||||
" lines | compares text files\n"
|
||||
|
|
@ -174,6 +176,8 @@ static void rz_diff_show_help(bool usage_only) {
|
|||
" | requires -0 <cmd> and -1 <cmd> is optional\n"
|
||||
" entries | compares entries found in the files\n"
|
||||
" fields | compares fields found in the files\n"
|
||||
" graphs | compares 2 functions and outputs in graphviz/dot format\n"
|
||||
" | requires -0 <fcn name|offset> and -1 <fcn name|offset> is optional\n"
|
||||
" imports | compares imports found in the files\n"
|
||||
" libraries | compares libraries found in the files\n"
|
||||
" sections | compares sections found in the files\n"
|
||||
|
|
@ -202,8 +206,8 @@ static void rz_diff_parse_arguments(int argc, const char **argv, DiffContext *ct
|
|||
rz_getopt_init(&opt, argc, argv, "hjqvACTa:b:d:t:0:1:");
|
||||
while ((c = rz_getopt_next(&opt)) != -1) {
|
||||
switch (c) {
|
||||
case '0': rz_diff_ctx_set_def(ctx, command_a, NULL, opt.arg); break;
|
||||
case '1': rz_diff_ctx_set_def(ctx, command_b, NULL, opt.arg); break;
|
||||
case '0': rz_diff_ctx_set_def(ctx, input_a, NULL, opt.arg); break;
|
||||
case '1': rz_diff_ctx_set_def(ctx, input_b, NULL, opt.arg); break;
|
||||
case 'A': rz_diff_ctx_set_def(ctx, compare_addresses, false, true); break;
|
||||
case 'C': rz_diff_ctx_set_def(ctx, colors, false, true); break;
|
||||
case 'T': rz_diff_ctx_set_def(ctx, show_time, false, true); break;
|
||||
|
|
@ -262,21 +266,35 @@ static void rz_diff_parse_arguments(int argc, const char **argv, DiffContext *ct
|
|||
} else if (!strcmp(type, "lines")) {
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_LINES);
|
||||
} else if (!strcmp(type, "functions")) {
|
||||
if (ctx->input_a) {
|
||||
rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' does not support -0.\n", type);
|
||||
} else if (ctx->input_b) {
|
||||
rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' does not support -1.\n", type);
|
||||
}
|
||||
ctx->option = DIFF_OPT_GRAPH;
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_FUNCTIONS);
|
||||
} else if (!strcmp(type, "classes")) {
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_CLASSES);
|
||||
} else if (!strcmp(type, "command")) {
|
||||
if (!ctx->command_a) {
|
||||
if (!ctx->input_a) {
|
||||
rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' requires -0 <command>.\n", type);
|
||||
}
|
||||
if (!ctx->command_b) {
|
||||
ctx->command_b = ctx->command_a;
|
||||
if (!ctx->input_b) {
|
||||
ctx->input_b = ctx->input_a;
|
||||
}
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_COMMAND);
|
||||
} else if (!strcmp(type, "entries")) {
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_ENTRIES);
|
||||
} else if (!strcmp(type, "fields")) {
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_FIELDS);
|
||||
} else if (!strcmp(type, "graphs")) {
|
||||
if (!ctx->input_a) {
|
||||
rz_diff_error_opt(ctx, DIFF_OPT_ERROR, "option -t '%s' requires -0 <fcn name|address>.\n", type);
|
||||
} else if (ctx->input_a && !ctx->input_b) {
|
||||
ctx->input_b = ctx->input_a;
|
||||
}
|
||||
ctx->option = DIFF_OPT_GRAPH;
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_PLOTDIFF);
|
||||
} else if (!strcmp(type, "imports")) {
|
||||
rz_diff_ctx_set_type(ctx, DIFF_TYPE_IMPORTS);
|
||||
} else if (!strcmp(type, "libraries")) {
|
||||
|
|
@ -409,7 +427,7 @@ static inline RzBinFile *core_get_file(RzCoreFile *cfile) {
|
|||
return rz_pvector_at(&cfile->binfiles, 0);
|
||||
}
|
||||
|
||||
static RzCoreFile *rz_diff_load_file_with_core(const char *filename, const char *architecture, ut32 arch_bits) {
|
||||
static RzCoreFile *rz_diff_load_file_with_core(const char *filename, const char *architecture, ut32 arch_bits, bool colors) {
|
||||
RzCore *core = NULL;
|
||||
RzCoreFile *cfile = NULL;
|
||||
RzBinFile *bfile = NULL;
|
||||
|
|
@ -421,7 +439,7 @@ static RzCoreFile *rz_diff_load_file_with_core(const char *filename, const char
|
|||
}
|
||||
rz_core_loadlibs(core, RZ_CORE_LOADLIBS_ALL, NULL);
|
||||
|
||||
rz_config_set_i(core->config, "scr.color", 0);
|
||||
rz_config_set_i(core->config, "scr.color", colors ? 1 : 0);
|
||||
rz_config_set_b(core->config, "scr.interactive", false);
|
||||
rz_config_set_b(core->config, "cfg.debug", false);
|
||||
core->print->scr_prompt = false;
|
||||
|
|
@ -1120,160 +1138,10 @@ static RzDiff *rz_diff_fields_new(DiffFile *dfile_a, DiffFile *dfile_b, bool com
|
|||
return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
|
||||
}
|
||||
|
||||
/**************************************** functions ***************************************/
|
||||
|
||||
static ut32 func_hash_addr(const DiffFunction *elem) {
|
||||
ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
|
||||
hash ^= (ut32)(elem->address >> 32);
|
||||
hash ^= (ut32)elem->address;
|
||||
hash ^= (ut32)elem->bits;
|
||||
hash ^= (ut32)elem->n_instructions;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int func_compare_addr(const DiffFunction *a, const DiffFunction *b) {
|
||||
st64 ret;
|
||||
IF_STRCMP_S(ret, a->name, b->name);
|
||||
ret = ((st64)b->address) - ((st64)a->address);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
ret = ((st64)b->n_instructions) - ((st64)a->n_instructions);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
return ((st64)b->bits) - ((st64)a->bits);
|
||||
}
|
||||
|
||||
static void func_stringify_addr(const DiffFunction *elem, RzStrBuf *sb) {
|
||||
rz_strbuf_setf(sb, "0x%016" PFMT64x " instrs: %-4d bits: %-2d %s\n",
|
||||
elem->address, elem->n_instructions, elem->bits, elem->name);
|
||||
}
|
||||
|
||||
static ut32 func_hash(const DiffFunction *elem) {
|
||||
ut32 hash = rz_diff_hash_data((const ut8 *)elem->name, strlen(elem->name));
|
||||
hash ^= (ut32)elem->bits;
|
||||
hash ^= (ut32)elem->n_instructions;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int func_compare(const DiffFunction *a, const DiffFunction *b) {
|
||||
st64 ret;
|
||||
IF_STRCMP_S(ret, a->name, b->name);
|
||||
ret = ((st64)b->n_instructions) - ((st64)a->n_instructions);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
return ((st64)b->bits) - ((st64)a->bits);
|
||||
}
|
||||
|
||||
static void func_stringify(const DiffFunction *elem, RzStrBuf *sb) {
|
||||
rz_strbuf_setf(sb, "instrs: %-4d bits: %-2d %s\n", elem->n_instructions, elem->bits, elem->name);
|
||||
}
|
||||
|
||||
static DiffFunction *func_new(RzAnalysisFunction *function) {
|
||||
DiffFunction *df = RZ_NEW(DiffFunction);
|
||||
if (!df) {
|
||||
return NULL;
|
||||
}
|
||||
df->name /* */ = strdup(function->name);
|
||||
df->bits /* */ = function->bits;
|
||||
df->address /* */ = function->addr;
|
||||
df->n_instructions = function->ninstr;
|
||||
return df;
|
||||
}
|
||||
|
||||
static void func_free(DiffFunction *func) {
|
||||
if (!func) {
|
||||
return;
|
||||
}
|
||||
free(func->name);
|
||||
free(func);
|
||||
}
|
||||
|
||||
static RzList *func_get_all_functions(const char *filename, const char *architecture, ut32 arch_bits) {
|
||||
RzList *list = NULL;
|
||||
RzList *functions = NULL;
|
||||
RzCoreFile *cfile = NULL;
|
||||
RzListIter *it = NULL;
|
||||
RzAnalysisFunction *fcn;
|
||||
DiffFunction *df = NULL;
|
||||
|
||||
cfile = rz_diff_load_file_with_core(filename, architecture, arch_bits);
|
||||
if (!cfile) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
functions = rz_analysis_function_list(cfile->core->analysis);
|
||||
if (!functions) {
|
||||
rz_diff_error("cannot get function list\n");
|
||||
goto func_get_all_functions_fail;
|
||||
}
|
||||
|
||||
list = rz_list_newf((RzListFree)func_free);
|
||||
if (!list) {
|
||||
rz_diff_error("cannot allocate list for functions\n");
|
||||
goto func_get_all_functions_fail;
|
||||
}
|
||||
|
||||
rz_list_foreach (functions, it, fcn) {
|
||||
if (!fcn) {
|
||||
continue;
|
||||
}
|
||||
df = func_new(fcn);
|
||||
if (!df) {
|
||||
rz_diff_error("cannot allocate function\n");
|
||||
goto func_get_all_functions_fail;
|
||||
}
|
||||
if (!rz_list_append(list, df)) {
|
||||
func_free(df);
|
||||
rz_diff_error("cannot insert function in list\n");
|
||||
goto func_get_all_functions_fail;
|
||||
}
|
||||
}
|
||||
|
||||
rz_core_free(cfile->core);
|
||||
return list;
|
||||
|
||||
func_get_all_functions_fail:
|
||||
if (cfile) {
|
||||
rz_core_free(cfile->core);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RzDiff *rz_diff_functions_new(DiffContext *ctx) {
|
||||
RzList *list_a = NULL;
|
||||
RzList *list_b = NULL;
|
||||
|
||||
list_a = func_get_all_functions(ctx->file_a, ctx->architecture, ctx->arch_bits);
|
||||
if (!list_a) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_b = func_get_all_functions(ctx->file_b, ctx->architecture, ctx->arch_bits);
|
||||
if (!list_b) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rz_list_sort(list_a, (RzListComparator)func_compare);
|
||||
rz_list_sort(list_b, (RzListComparator)func_compare);
|
||||
|
||||
RzDiffMethods methods = {
|
||||
.elem_at = (RzDiffMethodElemAt)rz_diff_list_elem_at,
|
||||
.elem_hash = (RzDiffMethodElemHash)(ctx->compare_addresses ? func_hash_addr : func_hash),
|
||||
.compare = (RzDiffMethodCompare)(ctx->compare_addresses ? func_compare_addr : func_compare),
|
||||
.stringify = (RzDiffMethodStringify)(ctx->compare_addresses ? func_stringify_addr : func_stringify),
|
||||
.ignore = NULL,
|
||||
};
|
||||
|
||||
return rz_diff_generic_new(list_a, rz_list_length(list_a), list_b, rz_list_length(list_b), &methods);
|
||||
}
|
||||
|
||||
/**************************************** commands ***************************************/
|
||||
|
||||
static char *execute_command(const char *command, const char *filename, const char *architecture, ut32 arch_bits) {
|
||||
RzCoreFile *cfile = rz_diff_load_file_with_core(filename, architecture, arch_bits);
|
||||
static char *execute_command(const char *command, const char *filename, DiffContext *ctx) {
|
||||
RzCoreFile *cfile = rz_diff_load_file_with_core(filename, ctx->architecture, ctx->arch_bits, ctx->colors);
|
||||
if (!cfile) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1287,15 +1155,15 @@ static RzDiff *rz_diff_command_new(DiffContext *ctx) {
|
|||
char *output_a = NULL;
|
||||
char *output_b = NULL;
|
||||
|
||||
output_a = execute_command(ctx->command_a, ctx->file_a, ctx->architecture, ctx->arch_bits);
|
||||
output_a = execute_command(ctx->input_a, ctx->file_a, ctx);
|
||||
if (!output_a) {
|
||||
rz_diff_error_ret(NULL, "cannot execute command '%s' on file '%s'\n", ctx->command_a, ctx->file_a);
|
||||
rz_diff_error_ret(NULL, "cannot execute command '%s' on file '%s'\n", ctx->input_a, ctx->file_a);
|
||||
}
|
||||
|
||||
output_b = execute_command(ctx->command_b, ctx->file_b, ctx->architecture, ctx->arch_bits);
|
||||
output_b = execute_command(ctx->input_b, ctx->file_b, ctx);
|
||||
if (!output_b) {
|
||||
free(output_a);
|
||||
rz_diff_error_ret(NULL, "cannot execute command '%s' on file '%s'\n", ctx->command_b, ctx->file_b);
|
||||
rz_diff_error_ret(NULL, "cannot execute command '%s' on file '%s'\n", ctx->input_b, ctx->file_b);
|
||||
}
|
||||
|
||||
RzDiff *diff = rz_diff_lines_new(output_a, output_b, NULL);
|
||||
|
|
@ -1304,7 +1172,7 @@ static RzDiff *rz_diff_command_new(DiffContext *ctx) {
|
|||
return diff;
|
||||
}
|
||||
|
||||
/**************************************** rz-diff ***************************************/
|
||||
/**************************************** unified ***************************************/
|
||||
|
||||
static bool rz_diff_unified_files(DiffContext *ctx) {
|
||||
size_t a_size = 0;
|
||||
|
|
@ -1350,9 +1218,6 @@ static bool rz_diff_unified_files(DiffContext *ctx) {
|
|||
case DIFF_TYPE_FIELDS:
|
||||
diff = rz_diff_fields_new(&dfile_a, &dfile_b, ctx->compare_addresses);
|
||||
break;
|
||||
case DIFF_TYPE_FUNCTIONS:
|
||||
diff = rz_diff_functions_new(ctx);
|
||||
break;
|
||||
case DIFF_TYPE_IMPORTS:
|
||||
diff = rz_diff_imports_new(&dfile_a, &dfile_b);
|
||||
break;
|
||||
|
|
@ -1400,11 +1265,6 @@ static bool rz_diff_unified_files(DiffContext *ctx) {
|
|||
result = true;
|
||||
|
||||
rz_diff_unified_files_bad:
|
||||
if (ctx->type == DIFF_TYPE_FUNCTIONS) {
|
||||
rz_list_free((RzList *)rz_diff_get_a(diff));
|
||||
rz_list_free((RzList *)rz_diff_get_b(diff));
|
||||
}
|
||||
|
||||
rz_diff_free(diff);
|
||||
rz_diff_file_close(&dfile_a);
|
||||
rz_diff_file_close(&dfile_b);
|
||||
|
|
@ -1413,6 +1273,72 @@ rz_diff_unified_files_bad:
|
|||
return result;
|
||||
}
|
||||
|
||||
/**************************************** graphs ***************************************/
|
||||
|
||||
static bool convert_offset_from_input(RzCore *core, const char *input, ut64 *offset) {
|
||||
if (rz_num_is_valid_input(NULL, input)) {
|
||||
*offset = rz_num_get_input_value(NULL, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
RzFlagItem *fi = rz_flag_get(core->flags, input);
|
||||
if (fi) {
|
||||
*offset = fi->offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rz_diff_graphs_files(DiffContext *ctx) {
|
||||
bool success = false;
|
||||
RzCoreFile *a = NULL;
|
||||
RzCoreFile *b = NULL;
|
||||
|
||||
a = rz_diff_load_file_with_core(ctx->file_a, ctx->architecture, ctx->arch_bits, ctx->colors);
|
||||
if (!a) {
|
||||
goto rz_diff_graphs_files_bad;
|
||||
}
|
||||
|
||||
b = rz_diff_load_file_with_core(ctx->file_b, ctx->architecture, ctx->arch_bits, ctx->colors);
|
||||
if (!b) {
|
||||
goto rz_diff_graphs_files_bad;
|
||||
}
|
||||
|
||||
if (ctx->type == DIFF_TYPE_PLOTDIFF) {
|
||||
ut64 offset_a = 0;
|
||||
ut64 offset_b = 0;
|
||||
|
||||
if (!convert_offset_from_input(a->core, ctx->input_a, &offset_a)) {
|
||||
rz_diff_error("cannot convert '%s' into an offset\n", ctx->input_a);
|
||||
goto rz_diff_graphs_files_bad;
|
||||
}
|
||||
|
||||
if (!convert_offset_from_input(b->core, ctx->input_b, &offset_b)) {
|
||||
rz_diff_error("cannot convert '%s' into an offset\n", ctx->input_b);
|
||||
goto rz_diff_graphs_files_bad;
|
||||
}
|
||||
if (!rz_core_gdiff_function_2_files(a->core, b->core, offset_a, offset_b)) {
|
||||
rz_diff_error("cannot diff graphs with inputs '%s' with '%s'\n", ctx->input_a, ctx->input_b);
|
||||
goto rz_diff_graphs_files_bad;
|
||||
}
|
||||
rz_core_diff_show_function(a->core, b->core, offset_a, ctx->mode == DIFF_MODE_JSON);
|
||||
} else {
|
||||
if (!rz_core_gdiff_2_files(a->core, b->core)) {
|
||||
rz_diff_error("cannot diff all graphs\n");
|
||||
goto rz_diff_graphs_files_bad;
|
||||
}
|
||||
rz_core_diff_show(a->core, b->core, ctx->mode == DIFF_MODE_JSON);
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
rz_diff_graphs_files_bad:
|
||||
rz_core_free(a ? a->core : NULL);
|
||||
rz_core_free(b ? b->core : NULL);
|
||||
return success;
|
||||
}
|
||||
|
||||
RZ_API int rz_main_rz_diff(int argc, const char **argv) {
|
||||
bool success = false;
|
||||
DiffContext ctx;
|
||||
|
|
@ -1426,6 +1352,9 @@ RZ_API int rz_main_rz_diff(int argc, const char **argv) {
|
|||
case DIFF_OPT_UNIFIED:
|
||||
success = rz_diff_unified_files(&ctx);
|
||||
break;
|
||||
case DIFF_OPT_GRAPH:
|
||||
success = rz_diff_graphs_files(&ctx);
|
||||
break;
|
||||
case DIFF_OPT_VERSION:
|
||||
rz_main_version_print("rz-diff");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ RZ_API RzBaseType *rz_type_db_get_base_type(RzTypeDB *typedb, const char *name)
|
|||
}
|
||||
|
||||
if (base_type) {
|
||||
free(base_type->name);
|
||||
base_type->name = sname;
|
||||
} else {
|
||||
free(sname);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ ec graph.box3 rgb:c0a060
|
|||
ec graph.box4 rgb:c0a060
|
||||
ec graph.true rgb:f0d090
|
||||
ec graph.false rgb:403010
|
||||
ec graph.trufae rgb:f0d090
|
||||
ec graph.ujump rgb:f0d090
|
||||
ec graph.current rgb:0000ff
|
||||
ec graph.traced rgb:0000ff
|
||||
ec graph.diff.unknown rgb:881798
|
||||
|
|
@ -172,7 +172,7 @@ EXPECT=<<EOF
|
|||
[90m##[0m graph.box4
|
||||
[32m##[0m graph.true
|
||||
[31m##[0m graph.false
|
||||
[34m##[0m graph.trufae
|
||||
[34m##[0m graph.ujump
|
||||
[34m##[0m graph.current
|
||||
[33m##[0m graph.traced
|
||||
[35m##[0m graph.diff.unknown
|
||||
|
|
@ -242,7 +242,7 @@ EXPECT=<<EOF
|
|||
[90m##[0m graph.box4
|
||||
[92m##[0m graph.true
|
||||
[91m##[0m graph.false
|
||||
[94m##[0m graph.trufae
|
||||
[94m##[0m graph.ujump
|
||||
[94m##[0m graph.current
|
||||
[93m##[0m graph.traced
|
||||
[35m##[0m graph.diff.unknown
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -53,7 +53,7 @@ ec graph.box3 rgb:881798
|
|||
ec graph.box4 rgb:767676
|
||||
ec graph.true rgb:13a10e
|
||||
ec graph.false rgb:c50f1f
|
||||
ec graph.trufae rgb:0037da
|
||||
ec graph.ujump rgb:0037da
|
||||
ec graph.current rgb:0037da
|
||||
ec graph.traced rgb:c19c00
|
||||
ec gui.cflow rgb:c19c00
|
||||
|
|
|
|||
Loading…
Reference in a new issue