diff --git a/libr/core/visual.c b/libr/core/visual.c index 73dcdc46ed..3c617ac8cf 100644 --- a/libr/core/visual.c +++ b/libr/core/visual.c @@ -2131,6 +2131,7 @@ R_API void r_core_visual_browse(RCore *core, const char *input) { " _ hud mode (V_)\n" " 1 bit editor (vd1)\n" " b blocks\n" + " a anal classes\n" " c classes\n" " C comments\n" " d debug traces\n" @@ -2212,6 +2213,9 @@ R_API void r_core_visual_browse(RCore *core, const char *input) { case 'c': // "vbc" r_core_visual_classes (core); break; + case 'a': // "vba" + r_core_visual_anal_classes (core); + break; case 'C': // "vbC" r_core_visual_comments (core); //r_core_cmd0 (core, "s $(CC~...)"); diff --git a/libr/core/vmenus.c b/libr/core/vmenus.c index 4d7e6d1920..69060ffe15 100644 --- a/libr/core/vmenus.c +++ b/libr/core/vmenus.c @@ -1345,6 +1345,218 @@ R_API int r_core_visual_classes(RCore *core) { return true; } +static void anal_class_print(RAnal *anal, const char *class_name) { + RVector *bases = r_anal_class_base_get_all (anal, class_name); + RVector *vtables = r_anal_class_vtable_get_all (anal, class_name); + RVector *methods = r_anal_class_method_get_all (anal, class_name); + + r_cons_print (class_name); + if (bases) { + RAnalBaseClass *base; + bool first = true; + r_vector_foreach (bases, base) { + if (first) { + r_cons_print (": "); + first = false; + } else { + r_cons_print (", "); + } + r_cons_print (base->class_name); + } + r_vector_free (bases); + } + + r_cons_print ("\n"); + + + if (vtables) { + RAnalVTable *vtable; + r_vector_foreach (vtables, vtable) { + r_cons_printf (" %2s vtable 0x%"PFMT64x" @ +0x%"PFMT64x" size:+0x%"PFMT64x"\n", vtable->id, vtable->addr, vtable->offset, vtable->size); + } + r_vector_free (vtables); + } + + r_cons_print ("\n"); + + if (methods) { + RAnalMethod *meth; + r_vector_foreach (methods, meth) { + r_cons_printf (" %s @ 0x%"PFMT64x, meth->name, meth->addr); + if (meth->vtable_offset >= 0) { + r_cons_printf (" (vtable + 0x%"PFMT64x")\n", (ut64)meth->vtable_offset); + } else { + r_cons_print ("\n"); + } + } + r_vector_free (methods); + } +} + + +static const char *show_anal_classes(RCore *core, char mode, int *idx, SdbList *list, const char *class_name) { + bool show_color = r_config_get_i (core->config, "scr.color"); + SdbListIter *iter; + SdbKv *kv; + int i = 0; + int skip = *idx - 10; + const char * cur_class; + r_cons_printf ("[hjkl_/Cfm]> anal classes:\n\n"); + + if (mode == 'd' && class_name) { + anal_class_print (core->anal, class_name); + return class_name; + } + + ls_foreach (list, iter, kv) { + if (*idx > 10) { + skip--; + if (skip > 0) { + i++; + continue; + } + } + class_name = sdbkv_key (kv); + + if (show_color) { + const char *pointer = "- "; + const char *txt_clr = ""; + + if (i == *idx) { + pointer = Color_GREEN ">>"; + txt_clr = Color_YELLOW; + cur_class = class_name; + } + r_cons_printf ("%s" Color_RESET " %02d" + " %s%s\n" Color_RESET, pointer, i, txt_clr, class_name); + } else { + r_cons_printf ("%s %02d %s\n", (i==*idx) ? ">>" : "- ", i, class_name); + } + + i++; + } + + return cur_class; +} +// TODO add other commands that Vbc has +// Should the classes be refreshed after command execution with : +// in case new class information would be added? +// Add grep? +R_API int r_core_visual_anal_classes(RCore *core) { + int ch, index = 0; + char command[1024]; + SdbList *list = r_anal_class_get_all (core->anal, true); + int oldcur = 0; + char mode = ' '; + const char *class_name = ""; + + if (r_list_empty (list)) { + r_cons_message ("No Classes"); + goto cleanup; + } + for (;;) { + int cols; + r_cons_clear00 (); + + class_name = show_anal_classes (core, mode, &index, list, class_name); + + /* update terminal size */ + (void) r_cons_get_size (&cols); + r_cons_visual_flush (); + ch = r_cons_readchar (); + if (ch == -1 || ch == 4) { + goto cleanup; + } + + ch = r_cons_arrow_to_hjkl (ch); // get ESC+char, return 'hjkl' char + switch (ch) { + case 'C': + r_config_toggle (core->config, "scr.color"); + break; + case 'J': + index += 10; + if (index >= list->length) { + index = list->length -1; + } + break; + case 'j': + if (++index >= list->length) { + index = 0; + } + break; + case 'k': + if (--index < 0) { + index = list->length - 1; + } + break; + case 'K': + index -= 10; + if (index < 0) { + index = 0; + } + break; + case 'g': + index = 0; + break; + case 'G': + index = list->length - 1; + break; + case 'h': + case 127: // backspace + case 'b': // back + case 'Q': + case 'c': + case 'q': + if (mode == ' ') { + goto cleanup; + } + mode = ' '; + index = oldcur; + break; + case 'l': + case ' ': + case '\r': + case '\n': + mode = 'd'; + break; + case '?': + r_cons_clear00 (); + r_cons_printf ( + "\nVF: Visual Classes help:\n\n" + " q - quit menu\n" + " j/k - down/up keys\n" + " h/b - go back\n" + " g/G - go first/last item\n" + " l/' ' - accept current selection\n" + " : - enter command\n"); + r_cons_flush (); + r_cons_any_key (NULL); + break; + case ':': + r_cons_show_cursor (true); + r_cons_set_raw (0); + command[0] = '\0'; + r_line_set_prompt (":> "); + if (r_cons_fgets (command, sizeof (command), 0, NULL) < 0) { + command[0]='\0'; + } + //line[strlen(line)-1]='\0'; + r_core_cmd (core, command, 1); + r_cons_set_raw (1); + r_cons_show_cursor (false); + if (command[0]) { + r_cons_any_key (NULL); + } + //cons_gotoxy(0,0); + r_cons_clear (); + break; + } + } +cleanup: + ls_free(list); + return true; +} + static int flag_name_sort(const void *a, const void *b) { const RFlagItem *fa = (const RFlagItem *)a; const RFlagItem *fb = (const RFlagItem *)b; diff --git a/libr/include/r_core.h b/libr/include/r_core.h index 3e3f9a193e..9c5f437505 100644 --- a/libr/include/r_core.h +++ b/libr/include/r_core.h @@ -441,6 +441,7 @@ R_API bool r_core_prevop_addr(RCore* core, ut64 start_addr, int numinstrs, ut64* R_API ut64 r_core_prevop_addr_force(RCore *core, ut64 start_addr, int numinstrs); R_API bool r_core_visual_hudstuff(RCore *core); R_API int r_core_visual_classes(RCore *core); +R_API int r_core_visual_anal_classes(RCore *core); R_API int r_core_visual_types(RCore *core); R_API int r_core_visual(RCore *core, const char *input); R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int is_interactive);