rizin/librz/core/tui/classes.c
Dean 59b38e6efa
Add /*<type>*/ comments everywhere (#2986)
Adds /*<type>*/ comments and a linter check from rz-bindgen to enforce
their existence and consistency

Also includes the following fixes made when adding the annotations:
* removed unused intern_table arguments in pyc_dis.c, pyc_dis.h, asm_pyc.c
* removed unused classes argument from place_nodes in agraph.c
* removed unused recurse and recurse_bb functions in canalysis.c
* removed unused vars field from RzPrint struct
* removed unused RzAnalysisType* structs from rz_analysis.h
* removed unused list field from RzEgg struct
* fixed bug in bp_plugin.c where duplication-checking logic iterates over the wrong list
* removed unused q_regs field from RzDebug struct
* removed unused backtrace field from RzDebugPlugin struct
* removed unused classes_list field from RzBinNXOObj struct
* removed unused methods_list and classes_list fields from RzBinZimgObj struct
2022-09-11 13:04:53 +08:00

596 lines
13 KiB
C

// SPDX-FileCopyrightText: 2009-2020 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <string.h>
#include <rz_core.h>
#include <rz_util.h>
#include "../core_private.h"
#include <rz_asm.h>
#include <rz_util/rz_print.h>
#include <rz_util/rz_strbuf.h>
// TODO: skip N first elements
// TODO: show only N elements of the list
// TODO: wrap index when out of boundaries
// TODO: Add support to show class fields too
// Segfaults - stack overflow, because of recursion
static void *show_class(RzCore *core, int mode, int *idx, RzBinClass *_c, const char *grep, RzList /*<RzBinClass *>*/ *list) {
bool show_color = rz_config_get_i(core->config, "scr.color");
RzListIter *iter;
RzBinClass *c, *cur = NULL;
RzBinSymbol *m, *mur = NULL;
RzBinField *f, *fur = NULL;
int i = 0;
int skip = *idx - 10;
bool found = false;
switch (mode) {
case 'c':
rz_cons_printf("[hjkl_/Cfm]> classes:\n\n");
rz_list_foreach (list, iter, c) {
if (grep) {
if (!rz_str_casestr(c->name, grep)) {
i++;
continue;
}
} else {
if (*idx > 10) {
skip--;
if (skip > 0) {
i++;
continue;
}
}
}
if (show_color) {
if (i == *idx) {
const char *clr = Color_BLUE;
rz_cons_printf(Color_GREEN ">>" Color_RESET " %02d %s0x%08" PFMT64x Color_YELLOW " %s\n" Color_RESET,
i, clr, c->addr, c->name);
} else {
rz_cons_printf("- %02d %s0x%08" PFMT64x Color_RESET " %s\n",
i, core->cons->context->pal.offset, c->addr, c->name);
}
} else {
rz_cons_printf("%s %02d 0x%08" PFMT64x " %s\n",
(i == *idx) ? ">>" : "- ", i, c->addr, c->name);
}
if (i++ == *idx) {
cur = c;
}
found = true;
}
if (!cur) {
*idx = i - 1;
if (!found) {
return NULL;
}
// rz_cons_clear00 ();
return NULL; // show_class (core, mode, idx, _c, "", list);
}
return cur;
case 'f':
// show fields
rz_cons_printf("[hjkl_/cFm]> fields of %s:\n\n", _c->name);
rz_list_foreach (_c->fields, iter, f) {
const char *name = f->name;
if (grep) {
if (!rz_str_casestr(name, grep)) {
i++;
continue;
}
} else {
if (*idx > 10) {
skip--;
if (skip > 0) {
i++;
continue;
}
}
}
char *mflags = strdup("");
if (rz_str_startswith(name, _c->name)) {
name += strlen(_c->name);
}
if (show_color) {
if (i == *idx) {
const char *clr = Color_BLUE;
rz_cons_printf(Color_GREEN ">>" Color_RESET " %02d %s0x%08" PFMT64x Color_YELLOW " %s %s\n" Color_RESET,
i, clr, f->vaddr, mflags, name);
} else {
rz_cons_printf("- %02d %s0x%08" PFMT64x Color_RESET " %s %s\n",
i, core->cons->context->pal.offset, f->vaddr, mflags, name);
}
} else {
rz_cons_printf("%s %02d 0x%08" PFMT64x " %s %s\n",
(i == *idx) ? ">>" : "- ", i, f->vaddr, mflags, name);
}
RZ_FREE(mflags);
if (i++ == *idx) {
fur = f;
}
}
if (!fur) {
*idx = i - 1;
if (rz_list_empty(_c->fields)) {
return NULL;
}
// rz_cons_clear00 ();
return NULL; // show_class (core, mode, idx, _c, grep, list);
}
return fur;
break;
case 'm':
// show methods
if (!_c) {
eprintf("No class selected.\n");
return mur;
}
rz_cons_printf("[hjkl_/cfM]> methods of %s\n\n", _c->name);
rz_list_foreach (_c->methods, iter, m) {
const char *name = m->dname ? m->dname : m->name;
char *mflags;
if (grep) {
if (!rz_str_casestr(name, grep)) {
i++;
continue;
}
} else {
if (*idx > 10) {
skip--;
if (skip > 0) {
i++;
continue;
}
}
}
mflags = rz_core_bin_method_flags_str(m->method_flags, 0);
if (show_color) {
if (rz_str_startswith(name, _c->name)) {
name += strlen(_c->name);
}
if (i == *idx) {
const char *clr = Color_BLUE;
rz_cons_printf(Color_GREEN ">>" Color_RESET " %02d %s0x%08" PFMT64x Color_YELLOW " %s %s\n" Color_RESET,
i, clr, m->vaddr, mflags, name);
} else {
rz_cons_printf("- %02d %s0x%08" PFMT64x Color_RESET " %s %s\n",
i, core->cons->context->pal.offset, m->vaddr, mflags, name);
}
} else {
rz_cons_printf("%s %02d 0x%08" PFMT64x " %s %s\n",
(i == *idx) ? ">>" : "- ", i, m->vaddr, mflags, name);
}
RZ_FREE(mflags);
if (i++ == *idx) {
mur = m;
}
}
if (!mur) {
*idx = i - 1;
if (rz_list_empty(_c->methods)) {
return NULL;
}
// rz_cons_clear00 ();
return NULL; // show_class (core, mode, idx, _c, grep, list);
}
return mur;
}
return NULL;
}
RZ_IPI int rz_core_visual_classes(RzCore *core) {
int ch, index = 0;
char cmd[1024];
int mode = 'c';
RzBinClass *cur = NULL;
RzBinSymbol *mur = NULL;
RzBinField *fur = NULL;
void *ptr;
int oldcur = 0;
char *grep = NULL;
bool grepmode = false;
RzList *list = rz_bin_get_classes(core->bin);
if (rz_list_empty(list)) {
rz_cons_message("No Classes");
return false;
}
for (;;) {
int cols;
rz_cons_clear00();
if (grepmode) {
rz_cons_printf("Grep: %s\n", grep ? grep : "");
}
ptr = show_class(core, mode, &index, cur, grep, list);
switch (mode) {
case 'f':
fur = (RzBinField *)ptr;
break;
case 'm':
mur = (RzBinSymbol *)ptr;
break;
case 'c':
cur = (RzBinClass *)ptr;
break;
}
/* update terminal size */
(void)rz_cons_get_size(&cols);
rz_cons_visual_flush();
ch = rz_cons_readchar();
if (ch == -1 || ch == 4) {
RZ_FREE(grep);
return false;
}
if (grepmode) {
switch (ch) {
case 127:
if (grep) {
int len = strlen(grep);
if (len < 1) {
grepmode = false;
} else {
grep[len - 1] = 0;
}
}
break;
case ' ':
case '\r':
case '\n':
RZ_FREE(grep);
grepmode = false;
break;
default:
grep = grep
? rz_str_appendf(grep, "%c", ch)
: rz_str_newf("%c", ch);
break;
}
continue;
}
ch = rz_cons_arrow_to_hjkl(ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'C':
rz_config_toggle(core->config, "scr.color");
break;
case '_':
if (rz_core_visual_hudclasses(core)) {
return true;
}
break;
case 'J': index += 10; break;
case 'j': index++; break;
case 'k':
if (--index < 0) {
index = 0;
}
break;
case 'K':
index -= 10;
if (index < 0) {
index = 0;
}
break;
case 'g':
index = 0;
break;
case 'G':
index = rz_list_length(list) - 1;
break;
case 'i': {
char *num = rz_cons_prompt("Index:", NULL);
if (num) {
index = atoi(num);
free(num);
}
} break;
case 'p':
if (mode == 'm' && mur) {
rz_core_seek(core, mur->vaddr, true);
rz_core_analysis_function_add(core, NULL, core->offset, false);
rz_core_cmd0(core, "pdf~..");
}
break;
case 'm': // methods
mode = 'm';
break;
case 'f': // fields
mode = 'f';
break;
case 'h':
case 127: // backspace
case 'b': // back
case 'Q':
case 'c':
case 'q':
if (mode == 'c') {
return true;
}
mode = 'c';
index = oldcur;
break;
case '/':
grepmode = true;
break;
case 'l':
case ' ':
case '\r':
case '\n':
if (mur && mode == 'm') {
rz_core_seek(core, mur->vaddr, true);
return true;
}
if (fur) {
rz_core_seek(core, fur->vaddr, true);
return true;
}
if (cur) {
oldcur = index;
index = 0;
mode = 'm';
}
break;
case '?':
rz_cons_clear00();
rz_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"
" i - specify index\n"
" / - grep mode\n"
" C - toggle colors\n"
" f - show class fields\n"
" m - show class methods\n"
" l/' ' - accept current selection\n"
" p - preview method disasm with less\n"
" : - enter command\n");
rz_cons_flush();
rz_cons_any_key(NULL);
break;
case ':':
rz_cons_show_cursor(true);
rz_cons_set_raw(0);
cmd[0] = '\0';
rz_line_set_prompt(":> ");
if (rz_cons_fgets(cmd, sizeof(cmd), 0, NULL) < 0) {
cmd[0] = '\0';
}
// line[strlen(line)-1]='\0';
rz_core_cmd(core, cmd, 1);
rz_cons_set_raw(1);
rz_cons_show_cursor(false);
if (cmd[0]) {
rz_cons_any_key(NULL);
}
// cons_gotoxy(0,0);
rz_cons_clear();
break;
}
}
return true;
}
static void analysis_class_print(RzAnalysis *analysis, const char *class_name) {
RzVector *bases = rz_analysis_class_base_get_all(analysis, class_name);
RzVector *vtables = rz_analysis_class_vtable_get_all(analysis, class_name);
RzVector *methods = rz_analysis_class_method_get_all(analysis, class_name);
rz_cons_print(class_name);
if (bases) {
RzAnalysisBaseClass *base;
bool first = true;
rz_vector_foreach(bases, base) {
if (first) {
rz_cons_print(": ");
first = false;
} else {
rz_cons_print(", ");
}
rz_cons_print(base->class_name);
}
rz_vector_free(bases);
}
rz_cons_print("\n");
if (vtables) {
RzAnalysisVTable *vtable;
rz_vector_foreach(vtables, vtable) {
rz_cons_printf(" %2s vtable 0x%" PFMT64x " @ +0x%" PFMT64x " size:+0x%" PFMT64x "\n", vtable->id, vtable->addr, vtable->offset, vtable->size);
}
rz_vector_free(vtables);
}
rz_cons_print("\n");
if (methods) {
RzAnalysisMethod *meth;
rz_vector_foreach(methods, meth) {
rz_cons_printf(" %s @ 0x%" PFMT64x, meth->name, meth->addr);
if (meth->vtable_offset >= 0) {
rz_cons_printf(" (vtable + 0x%" PFMT64x ")\n", (ut64)meth->vtable_offset);
} else {
rz_cons_print("\n");
}
}
rz_vector_free(methods);
}
}
static const char *show_analysis_classes(RzCore *core, char mode, int *idx, SdbList *list, const char *class_name) {
bool show_color = rz_config_get_i(core->config, "scr.color");
SdbListIter *iter;
SdbKv *kv;
int i = 0;
int skip = *idx - 10;
const char *cur_class = NULL;
rz_cons_printf("[hjkl_/Cfm]> analysis classes:\n\n");
if (mode == 'd' && class_name) {
analysis_class_print(core->analysis, 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;
}
rz_cons_printf("%s" Color_RESET " %02d"
" %s%s\n" Color_RESET,
pointer, i, txt_clr, class_name);
} else {
rz_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?
RZ_IPI int rz_core_visual_analysis_classes(RzCore *core) {
int ch, index = 0;
char command[1024];
SdbList *list = rz_analysis_class_get_all(core->analysis, true);
int oldcur = 0;
char mode = ' ';
const char *class_name = "";
if (rz_list_empty(list)) {
rz_cons_message("No Classes");
goto cleanup;
}
for (;;) {
int cols;
rz_cons_clear00();
class_name = show_analysis_classes(core, mode, &index, list, class_name);
/* update terminal size */
(void)rz_cons_get_size(&cols);
rz_cons_visual_flush();
ch = rz_cons_readchar();
if (ch == -1 || ch == 4) {
goto cleanup;
}
ch = rz_cons_arrow_to_hjkl(ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'C':
rz_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 '?':
rz_cons_clear00();
rz_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");
rz_cons_flush();
rz_cons_any_key(NULL);
break;
case ':':
rz_cons_show_cursor(true);
rz_cons_set_raw(0);
command[0] = '\0';
rz_line_set_prompt(":> ");
if (rz_cons_fgets(command, sizeof(command), 0, NULL) < 0) {
command[0] = '\0';
}
// line[strlen(line)-1]='\0';
rz_core_cmd(core, command, 1);
rz_cons_set_raw(1);
rz_cons_show_cursor(false);
if (command[0]) {
rz_cons_any_key(NULL);
}
// cons_gotoxy(0,0);
rz_cons_clear();
break;
}
}
cleanup:
ls_free(list);
return true;
}