Implement findNextWord in the interactive Visual Graph ##graph

This commit is contained in:
pancake 2020-04-22 11:21:48 +02:00
parent 311ad81894
commit 4b0e25caeb
6 changed files with 192 additions and 35 deletions

View File

@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2013-2019 - pancake */
/* radare - LGPL - Copyright 2013-2020 - pancake */
#include <r_cons.h>
#include <r_util/r_assert.h>
@ -218,6 +218,49 @@ R_API bool r_cons_canvas_gotoxy(RConsCanvas *c, int x, int y) {
return ret;
}
static char *canvas_string(RConsCanvas *c, size_t pos) {
int x, y;
char *s = calloc (c->w, c->h);
if (!s) {
return NULL;
}
char *p = s;
int ox = c->x;
int oy = c->y;
for (y = oy; y < c->h; y ++) {
for (x = (y == oy)? ox: 0; x < c->w; x ++) {
char ch = c->b[y][x];
const char *rune = r_cons_get_rune ((const ut8)ch);
if (rune) {
size_t rune_len = strlen (rune);
memcpy (p, rune, rune_len + 1);
p += rune_len;
} else {
*p = c->b[y][x];
}
}
}
return s;
}
static int count_newlines(char *s, size_t len, size_t *col) {
size_t nl = 0;
size_t nc = 0;
size_t i;
for (i = 0; i < len; i++) {
if (s[i] == '\n') {
nl++;
nc = 0;
} else {
nc ++;
}
}
if (col) {
*col = nc;
}
return nl;
}
R_API RConsCanvas *r_cons_canvas_new(int w, int h) {
if (w < 1 || h < 1) {
return NULL;
@ -265,7 +308,7 @@ R_API RConsCanvas *r_cons_canvas_new(int w, int h) {
c->attr = Color_RESET;
r_cons_canvas_clear (c);
return c;
beach: {
beach:
r_str_constpool_fini (&c->constpool);
int j;
for (j = 0; j < i; j++) {
@ -276,7 +319,6 @@ beach: {
free (c->b);
free (c);
return NULL;
}
}
R_API void r_cons_canvas_write(RConsCanvas *c, const char *s) {
@ -323,13 +365,13 @@ R_API void r_cons_canvas_write(RConsCanvas *c, const char *s) {
attr_len = slen <= 0 && s_part != s? 1: utf8_len;
if (attr_len > 0 && attr_x < c->blen[c->y]) {
__stampAttribute (c, c->y*c->w + attr_x, attr_len);
__stampAttribute (c, c->y * c->w + attr_x, attr_len);
}
s = s_part;
if (ch == '\n') {
c->attr = Color_RESET;
__stampAttribute (c, c->y*c->w + attr_x, 0);
__stampAttribute (c, c->y * c->w + attr_x, 0);
c->y++;
s++;
if (*s == '\0' || c->y >= c->h) {
@ -351,7 +393,7 @@ R_API char *r_cons_canvas_to_string(RConsCanvas *c) {
r_return_val_if_fail (c, NULL);
int x, y, olen = 0, attr_x = 0;
int is_first = true;
bool is_first = true;
for (y = 0; y < c->h; y++) {
olen += c->blen[y] + 1;
@ -376,7 +418,7 @@ R_API char *r_cons_canvas_to_string(RConsCanvas *c) {
if ((c->b[y][x] & 0xc0) != 0x80) {
const char *atr = __attributeAt (c, y * c->w + attr_x);
if (atr) {
int len = strlen (atr);
size_t len = strlen (atr);
memcpy (o + olen, atr, len);
olen += len;
}
@ -391,8 +433,9 @@ R_API char *r_cons_canvas_to_string(RConsCanvas *c) {
}
const char *rune = r_cons_get_rune ((const ut8)c->b[y][x]);
if (rune) {
strcpy (o + olen, rune);
olen += strlen (rune);
size_t rune_len = strlen (rune);
memcpy (o + olen, rune, rune_len + 1);
olen += rune_len;
} else {
o[olen++] = c->b[y][x];
}
@ -452,12 +495,12 @@ R_API int r_cons_canvas_resize(RConsCanvas *c, int w, int h) {
if (i < c->h) {
newline = realloc (c->b[i], sizeof *c->b[i] * (w + 1));
} else {
newline = malloc ((w + 1));
newline = malloc (w + 1);
}
c->blen[i] = w;
c->bsize[i] = w + 1;
if (!newline) {
int j;
size_t j;
for (j = 0; j <= i; j++) {
free (c->b[i]);
}

View File

@ -1,4 +1,4 @@
/* Copyright radare2 - 2014-2019 - pancake, ret2libc */
/* Copyright radare2 - 2014-2020 - pancake, ret2libc */
#include <r_core.h>
#include <r_cons.h>
@ -2058,13 +2058,11 @@ static void set_layout(RAGraph *g) {
backedge_info (g);
//restore_original_edges (g);
//remove_dummy_nodes (g);
/* free all temporary structures used during layout */
for (i = 0; i < g->n_layers; i++) {
free (g->layers[i].nodes);
}
free (g->layers);
r_list_free (g->long_edges);
r_list_free (g->back_edges);
@ -2413,7 +2411,7 @@ cleanup:
/* build the RGraph inside the RAGraph g, starting from the Call Graph
* information */
static int get_cgnodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
static bool get_cgnodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
RAnalFunction *f = r_anal_get_fcn_in (core->anal, core->offset, 0);
RANode *node, *fcn_anode;
RListIter *iter;
@ -2474,25 +2472,21 @@ static int get_cgnodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
return true;
}
static int reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
int is_c = g->is_callgraph;
static bool reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
const bool is_c = g->is_callgraph;
return is_c? get_cgnodes (g, core, fcn): get_bbnodes (g, core, fcn);
}
static void update_seek(RConsCanvas *can, RANode *n, int force) {
int x, y, w, h;
int doscroll = false;
if (!n) {
return;
}
x = n->x + can->sx;
y = n->y + can->sy;
w = can->w;
h = can->h;
doscroll = force || y < 0 || y + 5 > h || x + 5 > w || x + n->w + 5 < 0;
int x = n->x + can->sx;
int y = n->y + can->sy;
int w = can->w;
int h = can->h;
const bool doscroll = force || y < 0 || y + 5 > h || x + 5 > w || x + n->w + 5 < 0;
if (doscroll) {
if (n->w > w) { //too big for centering
can->sx = -n->x;
@ -2529,8 +2523,8 @@ static const RGraphNode *find_near_of(const RAGraph *g, const RGraphNode *cur, i
const RGraphNode *gn, *resgn = NULL;
const RANode *n, *acur = cur? get_anode (cur): NULL;
const int default_v = is_next? INT_MIN: INT_MAX;
const int start_y = acur? acur->y: default_v;
const int start_x = acur? acur->x: default_v;
const int start_y = acur? acur->y: default_v;
graph_foreach_anode (nodes, it, gn, n) {
// tab in horizontal layout is not correct, lets force vertical nextnode for now (g->layout == 0)
@ -3152,9 +3146,8 @@ static void agraph_set_zoom(RAGraph *g, int v) {
/* reload all the info in the nodes, depending on the type of the graph
* (callgraph, CFG, etc.), set the default layout for these nodes and center
* the screen on the selected one */
static int agraph_reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
static bool agraph_reload_nodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
r_agraph_reset (g);
return reload_nodes (g, core, fcn);
}
@ -3178,7 +3171,6 @@ static void move_current_node(RAGraph *g, int xdiff, int ydiff) {
xdiff = NORMALIZE_MOV (xdiff);
ydiff = NORMALIZE_MOV (ydiff);
}
n->x += xdiff;
n->y += ydiff;
}
@ -3234,7 +3226,7 @@ static void agraph_toggle_mini(RAGraph *g) {
agraph_set_layout ((RAGraph *) g);
}
static void agraph_follow_innodes (RAGraph *g, bool in) {
static void agraph_follow_innodes(RAGraph *g, bool in) {
int count = 0;
RListIter *iter;
RANode *an = get_anode (g->curnode);
@ -4046,6 +4038,114 @@ static bool toggle_bb(RCore *core, ut64 addr) {
return false;
}
typedef struct r_canvas_location {
int x;
int y;
} RPosition;
static const char *strstr_xy(const char *p, const char *s, int *x, int *y) {
const char *d = strstr (p, s);
if (!d) {
return NULL;
}
const char *q;
int nl = 0;
int nc = *x;
for (q = p; q < d; q++) {
if (*q == '\n') {
nl++;
*x = 0;
nc = 0;
} else {
nc++;
}
}
*x += nc;
*y += nl;
return d;
}
static char *get_graph_string(RCore *core) {
int c = r_config_get_i (core->config, "scr.color");
int u = r_config_get_i (core->config, "scr.utf8");
r_config_set_i (core->config, "scr.color", 0);
r_config_set_i (core->config, "scr.utf8", 0);
r_core_visual_graph (core, NULL, NULL, false);
char *s = strdup (r_cons_get_buffer ());
r_cons_reset ();
r_config_set_i (core->config, "scr.color", c);
r_config_set_i (core->config, "scr.utf8", u);
return s;
}
static void nextword(RCore *core, RConsCanvas *can, const char *word) {
r_return_if_fail (core && core->graph && can && word);
if (R_STR_ISEMPTY (word)) {
return;
}
RAGraphHits *gh = &core->graph->ghits;
if (gh->word_list.v.len && gh->old_word && !strcmp (word, gh->old_word)) {
RPosition *pos = r_pvector_at (&gh->word_list, gh->word_nth);
if (pos) {
gh->word_nth++;
} else {
gh->word_nth = 0;
pos = r_pvector_at (&gh->word_list, gh->word_nth);
}
if (pos) {
can->sx = pos->x;
can->sy = pos->y;
}
return;
} else {
r_pvector_fini (&gh->word_list);
r_pvector_init (&gh->word_list, free);
}
char *s = get_graph_string (core);
const char *p = s;
r_cons_clear00 ();
r_cons_flush ();
int ox = 0;
int oy = 0;
size_t count = 0;
const size_t MAX_COUNT = 4096;
int x = 0;
int y = 0;
bool first_x = true;
for (count = 0; count < MAX_COUNT; count++) {
x = 0;
const char *a = strstr_xy (p, word, &x, &y);
if (!a) {
break;
}
RPosition *pos = R_NEW0 (RPosition);
if (!pos) {
break;
}
if (first_x) {
gh->x_origin = x;
first_x = false;
}
const size_t yhalf = can->h / 6;
pos->y = -y + yhalf;
if (oy == pos->y) {
const size_t xhalf = can->w / 2;
pos->x = - (x - (ox * 2) - xhalf);
} else {
const size_t nhalf = can->w / 3;
pos->x = gh->x_origin - x + nhalf;
}
oy = pos->y;
ox = pos->x;
r_pvector_push (&gh->word_list, pos);
p = a + 1;
}
free (gh->old_word);
gh->old_word = strdup (word);
free (s);
return nextword (core, can, word);
}
R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int is_interactive) {
int o_asmqjmps_letter = core->is_asmqjmps_letter;
int o_scrinteractive = r_cons_is_interactive ();
@ -4242,6 +4342,9 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
get_bbupdate (g, core, fcn);
}
break;
case '\\':
nextword (core, can, r_config_get (core->config, "scr.highlight"));
break;
case 'b':
r_core_visual_browse (core, "");
break;
@ -4345,6 +4448,7 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
" \" - toggle graph.refs\n"
" # - toggle graph.hints\n"
" / - highlight text\n"
" \\ - scroll the graph canvas to the next highlight location\n"
" | - set cmd.gprompt\n"
" _ - enter hud selector\n"
" > - show function callgraph (see graph.refs)\n"
@ -4838,6 +4942,8 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
break;
}
}
RAGraphHits *gh = &core->graph->ghits;
r_pvector_fini (&gh->word_list);
r_cons_break_pop ();
r_config_set (core->config, "asm.comments", r_str_bool (asm_comments));
core->cons->event_resize = NULL;

View File

@ -26,6 +26,14 @@ typedef struct r_ascii_node_t {
bool is_mini;
} RANode;
typedef struct r_core_graph_hits_t {
char *old_word ;
RPVector word_list;
int word_nth;
int x_origin;
} RAGraphHits;
#define R_AGRAPH_MODE_NORMAL 0
#define R_AGRAPH_MODE_OFFSET 1
#define R_AGRAPH_MODE_MINI 2
@ -81,6 +89,7 @@ typedef struct r_ascii_graph_t {
int n_layers;
RList *dists; /* RList<struct dist_t> */
RList *edges; /* RList<AEdge> */
RAGraphHits ghits;
} RAGraph;
#ifdef R_API

View File

@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2009-2019 - pancake */
/* radare - LGPL - Copyright 2009-2020 - pancake */
#ifndef R2_CORE_H
#define R2_CORE_H

View File

@ -2468,7 +2468,7 @@ R_API int r_str_len_utf8_ansi(const char *str) {
}
// XXX must find across the ansi tags, as well as support utf8
R_API const char *r_strstr_ansi (const char *a, const char *b) {
R_API const char *r_strstr_ansi(const char *a, const char *b) {
const char *ch, *p = a;
do {
ch = strchr (p, '\x1b');

View File

@ -228,7 +228,6 @@ static void pvector_free_elem(void *e, void *user) {
elem_free (p);
}
R_API void r_pvector_init(RPVector *vec, RPVectorFree free) {
r_vector_init (&vec->v, sizeof (void *), free ? pvector_free_elem : NULL, free);
}