Introduce FAKE command descryptor type ##newshell (#20)

* Show ? if additional commands are present as sub-commands #newshell
* Show ?? for ? command, because `??` is a variable ##newshell
* Provide RzCmdDescDetailEntry.arg_str to better show arguments ##newshell
* Provide new FAKE RZ_CMD_DESC_TYPE ##newshell
* Move @?, |?, >? to FAKE entries ##newshell
* Additional help for @@, @@@, ~
* Fix windows/osx ci
This commit is contained in:
Riccardo Schirone 2020-10-08 15:31:54 +02:00 committed by GitHub
parent abdcc64a46
commit baea395572
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 381 additions and 119 deletions

View file

@ -621,8 +621,8 @@ jobs:
- name: Check that libraries can be used
shell: bash
run: |
echo -e "#include <r_util.h>\nint main(int argc, char **argv) { return r_str_newf (\"%s\", argv[0]) != NULL? 0: 1; }" > test.c
gcc -o test test.c $(pkg-config --libs --cflags r_util)
echo -e "#include <rz_util.h>\nint main(int argc, char **argv) { return rz_str_newf (\"%s\", argv[0]) != NULL? 0: 1; }" > test.c
gcc -o test test.c $(pkg-config --libs --cflags rz_util)
./test
test-osx-pkg:
@ -642,8 +642,8 @@ jobs:
run: rizin -qcq /bin/ls
- name: Check that libraries can be used
run: |
echo -e "#include <r_util.h>\nint main(int argc, char **argv) { return r_str_newf (\"%s\", argv[0]) != NULL? 0: 1; }" > test.c
clang -o test test.c $(pkg-config --libs --cflags r_util)
echo -e "#include <rz_util.h>\nint main(int argc, char **argv) { return rz_str_newf (\"%s\", argv[0]) != NULL? 0: 1; }" > test.c
clang -o test test.c $(pkg-config --libs --cflags rz_util)
./test
test-windows-clang_cl:
@ -681,8 +681,8 @@ jobs:
$env:PKG_CONFIG_PATH = "C:$env:HOMEPATH\AppData\Local\Programs\rizin\lib\pkgconfig"
$env:PKG_CONFIG_PATH
pkg-config --list-all
echo "#include <r_util.h>`nint main(int argc, char **argv) { return r_str_newf (`"%s`", argv[0]) != NULL? 0: 1; }" > test.c
cl -IC:$env:HOMEPATH\AppData\Local\Programs\rizin\include\librz -IC:$env:HOMEPATH\AppData\Local\Programs\rizin\include\librz\sdb /Fetest.exe test.c /link /libpath:C:$env:HOMEPATH\AppData\Local\Programs\rizin\lib r_util.lib
echo "#include <rz_util.h>`nint main(int argc, char **argv) { return rz_str_newf (`"%s`", argv[0]) != NULL? 0: 1; }" > test.c
cl -IC:$env:HOMEPATH\AppData\Local\Programs\rizin\include\librz -IC:$env:HOMEPATH\AppData\Local\Programs\rizin\include\librz\sdb /Fetest.exe test.c /link /libpath:C:$env:HOMEPATH\AppData\Local\Programs\rizin\lib rz_util.lib
.\test.exe
create-release:

View file

@ -5188,22 +5188,9 @@ DEFINE_HANDLE_TS_FCN_AND_SYMBOL(redirect_command) {
}
DEFINE_HANDLE_TS_FCN_AND_SYMBOL(help_command) {
// TODO: traverse command tree to print help
// FIXME: once we have a command tree, this special handling should be removed
size_t node_str_len = strlen (node_string);
if (!strcmp (node_string, "@?")) {
rz_core_cmd_help (state->core, help_msg_at);
} else if (!strcmp (node_string, "@@?")) {
rz_core_cmd_help (state->core, help_msg_at_at);
} else if (!strcmp (node_string, "@@@?")) {
rz_core_cmd_help (state->core, help_msg_at_at_at);
} else if (!strcmp (node_string, "|?")) {
rz_core_cmd_help (state->core, help_msg_vertical_bar);
} else if (!strcmp (node_string, "~?")) {
rz_cons_grep_help ();
} else if (!strcmp (node_string, ">?")) {
rz_core_cmd_help (state->core, help_msg_greater_sign);
} else if (node_str_len >= 2 && !strcmp (node_string + node_str_len - 2, "?*")) {
if (node_str_len >= 2 && !strcmp (node_string + node_str_len - 2, "?*")) {
// TODO: get recursive help from RzCmdDesc
int detail = 0;
if (node_str_len > 3 && node_string[node_str_len - 3] == '?') {
detail++;
@ -7126,55 +7113,61 @@ RZ_API void rz_core_cmd_init(RzCore *core) {
RzCmdDescType type;
RzCmdArgvCb argv_cb;
} cmds[] = {
{"!", "run system command", cmd_system, NULL, &system_help},
{"_", "print last output", cmd_last, NULL, &underscore_help},
{"#", "calculate hash", cmd_hash, NULL, &hash_help},
{"$", "alias", cmd_alias, NULL, &alias_help},
{"%", "short version of 'env' command", cmd_env, NULL, &percentage_help, NULL, RZ_CMD_DESC_TYPE_ARGV, env_handler},
{"&", "tasks", cmd_tasks, NULL, &tasks_help},
{"(", "macro", cmd_macro, cmd_macro_init, &macro_help},
{"*", "pointer read/write", cmd_pointer, NULL, &pointer_help, NULL, RZ_CMD_DESC_TYPE_ARGV, pointer_handler},
{"-", "open cfg.editor and run script", cmd_stdin, NULL, &stdin_help},
{".", "interpret", cmd_interpret, NULL, &interpret_help},
{"/", "search kw, pattern aes", cmd_search, cmd_search_init, &search_help},
{"=", "io pipe", cmd_rap, NULL, &rap_help},
{"?", "help message", cmd_help, cmd_help_init, &help_help},
{"\\", "alias for =!", cmd_rap_run, NULL, &rap_run_help},
{"'", "alias for =!", cmd_rap_run, NULL, &rap_run_help},
{"0", "alias for s 0x", cmd_ox, NULL, &zero_help},
{"a", "analysis", cmd_anal, cmd_anal_init, &anal_help},
{"b", "change block size", cmd_bsize, NULL, &b_help},
{"c", "compare memory", cmd_cmp, cmd_cmp_init, &c_help},
{"C", "code metadata", cmd_meta, cmd_meta_init, &C_help},
{"d", "debugger operations", cmd_debug, cmd_debug_init, &d_help},
{"e", "evaluate configuration variable", cmd_eval, cmd_eval_init, &e_help},
{"f", "get/set flags", cmd_flag, cmd_flag_init, &f_help},
{"g", "egg manipulation", cmd_egg, cmd_egg_init, &g_help},
{"i", "get file info", cmd_info, cmd_info_init, &i_help},
{"k", "perform sdb query", cmd_kuery, NULL, &k_help},
{"l", "list files and directories", cmd_ls, NULL, &l_help},
{"j", "join the contents of the two files", cmd_join, NULL, &j_help},
{"m", "make directory and move files", cmd_m, NULL, &m_help},
{"h", "show the top n number of line in file", cmd_head, NULL, &h_help},
{"L", "manage dynamically loaded plugins", cmd_plugins, NULL, &L_help},
{"o", "open or map file", cmd_open, cmd_open_init, &o_help},
{"p", "print current block", cmd_print, cmd_print_init, &p_help},
{"P", "project", cmd_project, cmd_project_init, &P_help},
{"q", "exit program session", cmd_quit, cmd_quit_init, &q_help},
{"Q", "alias for q!", cmd_Quit, NULL, &Q_help},
{":", "long commands starting with :", cmd_colon, NULL, &colon_help},
{"r", "change file size", cmd_resize, NULL, &rz_help},
{"s", "seek to an offset", cmd_seek, cmd_seek_init, &s_help},
{"t", "type information (cparse)", cmd_type, cmd_type_init, &t_help},
{"T", "Text log utility", cmd_log, cmd_log_init, &T_help},
{"u", "uname/undo", cmd_undo, NULL, &u_help},
{"<", "pipe into RzCons.readChar", cmd_pipein, NULL, &pipein_help},
{"V", "enter visual mode", cmd_visual, NULL, &V_help},
{"v", "enter visual mode", cmd_panels, NULL, &v_help},
{"w", "write bytes", cmd_write, cmd_write_init, &w_help, &w_group_help, RZ_CMD_DESC_TYPE_GROUP, w_handler},
{"x", "alias for px", cmd_hexdump, NULL, &x_help},
{"y", "yank bytes", cmd_yank, NULL, &y_help},
{"z", "zignatures", cmd_zign, cmd_zign_init, &z_help},
{ "!", "run system command", cmd_system, NULL, &system_help },
{ "_", "print last output", cmd_last, NULL, &underscore_help },
{ "#", "calculate hash", cmd_hash, NULL, &hash_help },
{ "$", "alias", cmd_alias, NULL, &alias_help },
{ "%", "short version of 'env' command", cmd_env, NULL, &percentage_help, NULL, RZ_CMD_DESC_TYPE_ARGV, env_handler },
{ "&", "tasks", cmd_tasks, NULL, &tasks_help },
{ "(", "macro", cmd_macro, cmd_macro_init, &macro_help },
{ "*", "pointer read/write", cmd_pointer, NULL, &pointer_help, NULL, RZ_CMD_DESC_TYPE_ARGV, pointer_handler },
{ "-", "open cfg.editor and run script", cmd_stdin, NULL, &stdin_help },
{ ".", "interpret", cmd_interpret, NULL, &interpret_help },
{ "/", "search kw, pattern aes", cmd_search, cmd_search_init, &search_help },
{ "=", "io pipe", cmd_rap, NULL, &rap_help },
{ "?", "help message", cmd_help, cmd_help_init, &help_help },
{ "\\", "alias for =!", cmd_rap_run, NULL, &rap_run_help },
{ "'", "alias for =!", cmd_rap_run, NULL, &rap_run_help },
{ "0", "alias for s 0x", cmd_ox, NULL, &zero_help },
{ "a", "analysis", cmd_anal, cmd_anal_init, &anal_help },
{ "b", "change block size", cmd_bsize, NULL, &b_help },
{ "c", "compare memory", cmd_cmp, cmd_cmp_init, &c_help },
{ "C", "code metadata", cmd_meta, cmd_meta_init, &C_help },
{ "d", "debugger operations", cmd_debug, cmd_debug_init, &d_help },
{ "e", "evaluate configuration variable", cmd_eval, cmd_eval_init, &e_help },
{ "f", "get/set flags", cmd_flag, cmd_flag_init, &f_help },
{ "g", "egg manipulation", cmd_egg, cmd_egg_init, &g_help },
{ "i", "get file info", cmd_info, cmd_info_init, &i_help },
{ "k", "perform sdb query", cmd_kuery, NULL, &k_help },
{ "l", "list files and directories", cmd_ls, NULL, &l_help },
{ "j", "join the contents of the two files", cmd_join, NULL, &j_help },
{ "m", "make directory and move files", cmd_m, NULL, &m_help },
{ "h", "show the top n number of line in file", cmd_head, NULL, &h_help },
{ "L", "manage dynamically loaded plugins", cmd_plugins, NULL, &L_help },
{ "o", "open or map file", cmd_open, cmd_open_init, &o_help },
{ "p", "print current block", cmd_print, cmd_print_init, &p_help },
{ "P", "project", cmd_project, cmd_project_init, &P_help },
{ "q", "exit program session", cmd_quit, cmd_quit_init, &q_help },
{ "Q", "alias for q!", cmd_Quit, NULL, &Q_help },
{ ":", "long commands starting with :", cmd_colon, NULL, &colon_help },
{ "r", "change file size", cmd_resize, NULL, &rz_help },
{ "s", "seek to an offset", cmd_seek, cmd_seek_init, &s_help },
{ "t", "type information (cparse)", cmd_type, cmd_type_init, &t_help },
{ "T", "Text log utility", cmd_log, cmd_log_init, &T_help },
{ "u", "uname/undo", cmd_undo, NULL, &u_help },
{ "<", "pipe into RzCons.readChar", cmd_pipein, NULL, &pipein_help },
{ "V", "enter visual mode", cmd_visual, NULL, &V_help },
{ "v", "enter visual mode", cmd_panels, NULL, &v_help },
{ "w", "write bytes", cmd_write, cmd_write_init, &w_help, &w_group_help, RZ_CMD_DESC_TYPE_GROUP, w_handler },
{ "x", "alias for px", cmd_hexdump, NULL, &x_help },
{ "y", "yank bytes", cmd_yank, NULL, &y_help },
{ "z", "zignatures", cmd_zign, cmd_zign_init, &z_help },
{ "@", "temporary modifiers", NULL, NULL, &tmp_modifier_help, NULL, RZ_CMD_DESC_TYPE_FAKE },
{ "@@", "iterators", NULL, NULL, &iterator_help, NULL, RZ_CMD_DESC_TYPE_FAKE },
{ "@@@", "foreach", NULL, NULL, &foreach_help, NULL, RZ_CMD_DESC_TYPE_FAKE },
{ ">", "redirection", NULL, NULL, &redirection_help, NULL, RZ_CMD_DESC_TYPE_FAKE },
{ "|", "pipe", NULL, NULL, &pipe_help, NULL, RZ_CMD_DESC_TYPE_FAKE },
{ "~", "grep", NULL, NULL, &grep_help, NULL, RZ_CMD_DESC_TYPE_FAKE },
};
core->rcmd = rz_cmd_new ();
@ -7189,7 +7182,9 @@ RZ_API void rz_core_cmd_init(RzCore *core) {
RzCmdDesc *root = rz_cmd_get_root (core->rcmd);
size_t i;
for (i = 0; i < RZ_ARRAY_SIZE (cmds); i++) {
rz_cmd_add (core->rcmd, cmds[i].cmd, cmds[i].cb);
if (cmds[i].cb) {
rz_cmd_add (core->rcmd, cmds[i].cmd, cmds[i].cb);
}
RzCmdDesc *cd;
switch (cmds[i].type) {
@ -7205,6 +7200,9 @@ RZ_API void rz_core_cmd_init(RzCore *core) {
case RZ_CMD_DESC_TYPE_GROUP:
cd = rz_cmd_desc_group_new (core->rcmd, root, cmds[i].cmd, cmds[i].argv_cb, cmds[i].help, cmds[i].group_help);
break;
case RZ_CMD_DESC_TYPE_FAKE:
cd = rz_cmd_desc_fake_new (core->rcmd, root, cmds[i].cmd, cmds[i].help);
break;
}
if (cmds[i].descriptor_init) {
cmds[i].descriptor_init (core, cd);

View file

@ -52,6 +52,7 @@ static bool cmd_desc_set_parent(RzCmdDesc *cd, RzCmdDesc *parent) {
case RZ_CMD_DESC_TYPE_INNER:
break;
case RZ_CMD_DESC_TYPE_ARGV:
case RZ_CMD_DESC_TYPE_FAKE:
rz_warn_if_reached ();
return false;
}
@ -179,12 +180,8 @@ RZ_API RzCmdDesc *rz_cmd_get_desc(RzCmd *cmd, const char *cmd_identifier) {
if (cd) {
switch (cd->type) {
case RZ_CMD_DESC_TYPE_ARGV:
if (!is_exact_match) {
break;
}
res = cd;
goto out;
case RZ_CMD_DESC_TYPE_GROUP:
case RZ_CMD_DESC_TYPE_FAKE:
if (!is_exact_match) {
break;
}
@ -459,16 +456,24 @@ static void fill_children_chars(RStrBuf *sb, RzCmdDesc *cd) {
rz_strbuf_init (&csb);
void **it;
bool has_other_commands = false;
rz_cmd_desc_children_foreach (cd, it) {
RzCmdDesc *child = *(RzCmdDesc **)it;
if (rz_str_startswith (child->name, cd->name) && strlen (child->name) == strlen (cd->name) + 1) {
rz_strbuf_appendf (&csb, "%c", child->name[strlen (cd->name)]);
} else if (strcmp (child->name, cd->name)){
has_other_commands = true;
}
}
if (rz_strbuf_is_empty (&csb) || rz_strbuf_length (&csb) >= MAX_CHILDREN_SHOW) {
rz_strbuf_fini (&csb);
rz_strbuf_set (&csb, "?");
has_other_commands = false;
}
if (has_other_commands) {
rz_strbuf_append (&csb, "?");
}
if (!cd->n_children || rz_cmd_desc_has_handler (cd)) {
@ -576,13 +581,49 @@ static char *argv_group_get_help(RzCmd *cmd, RzCmdDesc *cd, bool use_color) {
return rz_strbuf_drain (sb);
}
static char *argv_get_help(RzCmd *cmd, RzCmdDesc *cd, RzCmdParsedArgs *a, size_t detail, bool use_color) {
static void fill_details(RzCmdDesc *cd, RStrBuf *sb, bool use_color) {
if (!cd->help->details) {
return;
}
RzCons *cons = rz_cons_singleton ();
const char *pal_help_color = use_color? cons->context->pal.help: "",
*pal_input_color = use_color? cons->context->pal.input: "",
*pal_label_color = use_color? cons->context->pal.label: "",
*pal_args_color = use_color? cons->context->pal.args: "",
*pal_reset = use_color? cons->context->pal.reset: "";
const RzCmdDescDetail *detail_it = cd->help->details;
while (detail_it->name) {
if (!RZ_STR_ISEMPTY(detail_it->name)) {
rz_strbuf_appendf (sb, "\n%s%s:%s\n", pal_label_color, detail_it->name, pal_reset);
}
const RzCmdDescDetailEntry *entry_it = detail_it->entries;
size_t max_len = 0;
while (entry_it->text) {
size_t len = strlen (entry_it->text) + strlen0 (entry_it->arg_str);
if (max_len < len) {
max_len = len;
}
entry_it++;
}
entry_it = detail_it->entries;
while (entry_it->text) {
size_t len = strlen (entry_it->text) + strlen0 (entry_it->arg_str);
size_t padding = len < max_len ? max_len - len : 0;
const char *arg_str = entry_it->arg_str ? entry_it->arg_str : "";
rz_strbuf_appendf (sb, "| %s%s%s%s %*s%s# %s%s\n",
pal_input_color, entry_it->text,
pal_args_color, arg_str,
padding, "",
pal_help_color, entry_it->comment, pal_reset);
entry_it++;
}
detail_it++;
}
}
static char *argv_get_help(RzCmd *cmd, RzCmdDesc *cd, size_t detail, bool use_color) {
RStrBuf *sb = rz_strbuf_new (NULL);
fill_usage_strbuf (sb, cd, use_color);
@ -594,33 +635,7 @@ static char *argv_get_help(RzCmd *cmd, RzCmdDesc *cd, RzCmdParsedArgs *a, size_t
if (cd->help->description) {
rz_strbuf_appendf (sb, "\n%s\n", cd->help->description);
}
if (cd->help->details) {
const RzCmdDescDetail *detail_it = cd->help->details;
while (detail_it->name) {
rz_strbuf_appendf (sb, "\n%s%s:%s\n", pal_label_color, detail_it->name, pal_reset);
const RzCmdDescDetailEntry *entry_it = detail_it->entries;
size_t max_len = 0;
while (entry_it->text) {
size_t len = strlen (entry_it->text);
if (max_len < len) {
max_len = len;
}
entry_it++;
}
entry_it = detail_it->entries;
while (entry_it->text) {
size_t len = strlen (entry_it->text);
size_t padding = len < max_len? max_len - len: 0;
rz_strbuf_appendf (sb, "| %s%s%s %*s%s# %s%s\n",
pal_input_color, entry_it->text, pal_reset,
padding, "",
pal_help_color, entry_it->comment, pal_reset);
entry_it++;
}
detail_it++;
}
}
fill_details (cd, sb, use_color);
return rz_strbuf_drain (sb);
default:
rz_strbuf_free (sb);
@ -628,6 +643,11 @@ static char *argv_get_help(RzCmd *cmd, RzCmdDesc *cd, RzCmdParsedArgs *a, size_t
}
}
static char *fake_get_help(RzCmd *cmd, RzCmdDesc *cd, bool use_color) {
// abuse detail=2 of the argv help as they show essentially the same info
return argv_get_help (cmd, cd, 2, use_color);
}
static char *oldinput_get_help(RzCmd *cmd, RzCmdDesc *cd, RzCmdParsedArgs *a) {
const char *s = NULL;
rz_cons_push ();
@ -676,7 +696,12 @@ RZ_API char *rz_cmd_get_help(RzCmd *cmd, RzCmdParsedArgs *args, bool use_color)
}
return argv_group_get_help (cmd, cd, use_color);
}
return argv_get_help (cmd, cd, args, detail, use_color);
return argv_get_help (cmd, cd, detail, use_color);
case RZ_CMD_DESC_TYPE_FAKE:
if (detail != 1) {
return NULL;
}
return fake_get_help (cmd, cd, use_color);
case RZ_CMD_DESC_TYPE_OLDINPUT:
return oldinput_get_help (cmd, cd, args);
case RZ_CMD_DESC_TYPE_INNER:
@ -1313,6 +1338,11 @@ RZ_API RzCmdDesc *rz_cmd_desc_oldinput_new(RzCmd *cmd, RzCmdDesc *parent, const
return res;
}
RZ_API RzCmdDesc *rz_cmd_desc_fake_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, const RzCmdDescHelp *help) {
rz_return_val_if_fail (cmd && parent && name && help, NULL);
return create_cmd_desc (cmd, parent, RZ_CMD_DESC_TYPE_FAKE, name, help, true);
}
RZ_API RzCmdDesc *rz_cmd_desc_parent(RzCmdDesc *cd) {
rz_return_val_if_fail (cd, NULL);
return cd->parent;
@ -1325,6 +1355,7 @@ RZ_API bool rz_cmd_desc_has_handler(RzCmdDesc *cd) {
return cd->d.argv_data.cb;
case RZ_CMD_DESC_TYPE_OLDINPUT:
return cd->d.oldinput_data.cb;
case RZ_CMD_DESC_TYPE_FAKE:
case RZ_CMD_DESC_TYPE_INNER:
return false;
case RZ_CMD_DESC_TYPE_GROUP:

View file

@ -2,6 +2,203 @@
// root helps
const RzCmdDescDetailEntry tmp_modifier_detail_entries[] = {
{ .text = "<cmd> @", .arg_str = " <addr>", .comment = "temporary seek to <addr>" },
{ .text = "<cmd> @", .arg_str = " <addr>!<blocksize>", .comment = "temporary seek to <addr> and set blocksize to <blocksize>" },
{ .text = "<cmd> @..", .arg_str = "<addr>", .comment = "temporary partial address seek (see s..)" },
{ .text = "<cmd> @!", .arg_str = "<blocksize>", .comment = "temporary change the block size" },
{ .text = "<cmd> @{", .arg_str = "<from> <to>}", .comment = "temporary set from and to for commands supporting ranges" },
{ .text = "<cmd> @a:", .arg_str = "<arch>[:<bits>]", .comment = "temporary set arch and bits, if specified" },
{ .text = "<cmd> @b:", .arg_str = "<bits>", .comment = "temporary set asm.bits" },
{ .text = "<cmd> @B:", .arg_str = "<nth>", .comment = "temporary seek to nth instruction in current basic block (negative numbers too)" },
{ .text = "<cmd> @e:", .arg_str = "<k>=<v>[,<k>=<v>]", .comment = "temporary change eval vars (multiple vars separated by comma)" },
{ .text = "<cmd> @f:", .arg_str = "<file>", .comment = "temporary replace block with file contents" },
{ .text = "<cmd> @F:", .arg_str = "<flagspace>", .comment = "temporary change flag space" },
{ .text = "<cmd> @i:", .arg_str = "<nth.op>", .comment = "temporary seek to the Nth relative instruction" },
{ .text = "<cmd> @k:", .arg_str = "<key>", .comment = "temporary seek at value of sdb key `key`" },
{ .text = "<cmd> @o:", .arg_str = "<fd>", .comment = "temporary switch to another fd" },
{ .text = "<cmd> @r:", .arg_str = "<reg>", .comment = "temporary seek to register value" },
{ .text = "<cmd> @s:", .arg_str = "<string>", .comment = "temporary replace block with string" },
{ .text = "<cmd> @x:", .arg_str = "<hexstring>", .comment = "temporary replace block with hexstring" },
{ 0 },
};
const RzCmdDescDetail tmp_modifier_detail[] = {
{ .name = "", .entries = tmp_modifier_detail_entries },
{ 0 },
};
const RzCmdDescHelp tmp_modifier_help = {
.summary = "'@' help",
.options = "?",
.details = tmp_modifier_detail,
.usage = "<cmd> <@> <args>",
};
const RzCmdDescDetailEntry iterator_detail_entries[] = {
{ .text = "<cmd> @@", .arg_str = " <glob>", .comment = "run <cmd> over all flags matching <glob> in current flagspace. <glob> may contain `*` to indicate multiple chars" },
{ .text = "<cmd> @@dbt[abs]", .arg_str = "", .comment = "run <cmd> on every backtrace address, bp or sp" },
{ .text = "<cmd> @@.", .arg_str = "<file>", .comment = "run <cmd> over the offsets specified in <file>, one per line" },
{ .text = "<cmd> @@=", .arg_str = "<addr1> [<addr2> ...]", .comment = "run <cmd> over the listed addresses" },
{ .text = "<cmd> @@/", .arg_str = "<search-cmd>", .comment = "run <cmd> over the search results of /<search-cmd>" },
{ .text = "<cmd> @@k", .arg_str = " <sdbquery>", .comment = "run <cmd> over all offsets return by the sdb query <sdbquery>" },
{ .text = "<cmd> @@t", .arg_str = "", .comment = "run <cmd> over all threads" },
{ .text = "<cmd> @@b", .arg_str = "", .comment = "run <cmd> over all basic blocks of the current function" },
{ .text = "<cmd> @@i", .arg_str = "", .comment = "run <cmd> over all instructions of the current function" },
{ .text = "<cmd> @@iS", .arg_str = "", .comment = "run <cmd> over all sections" },
{ .text = "<cmd> @@f", .arg_str = "", .comment = "run <cmd> over all functions" },
{ .text = "<cmd> @@f:", .arg_str = "<glob>", .comment = "run <cmd> over all function matching <glob>. <glob> may contain `*` to indicate multiple chars" },
{ .text = "<cmd> @@s:", .arg_str = "<from> <to> <step>", .comment = "run <cmd> on all addresses starting from <from> and going up to <to> (included), with a step <step>." },
{ .text = "<cmd> @@c:", .arg_str = "<cmd2>", .comment = "run <cmd> on all addresses in the output of <cmd2>" },
{ 0 },
};
const RzCmdDescDetail iterator_detail[] = {
{ .name = "", .entries = iterator_detail_entries },
{ 0 },
};
const RzCmdDescHelp iterator_help = {
.summary = "'@@' help",
.options = "?",
.details = iterator_detail,
.usage = "<cmd> <@@> <args>",
};
const RzCmdDescDetailEntry foreach_detail_entries[] = {
{ .text = "<cmd> @@@=", .arg_str = "<addr> <size> (<addr> <size> ...)", .comment = "run <cmd> on each <addr> and set blocksize to <size>" },
{ .text = "<cmd> @@@b", .arg_str = "", .comment = "run <cmd> on each basic block of current function" },
{ .text = "<cmd> @@@c:", .arg_str = "<cmd2>", .comment = "same as <cmd>@@@=`<cmd2>`" },
{ .text = "<cmd> @@@C:", .arg_str = "<string>", .comment = "run <cmd> on each comment matching <string>" },
{ .text = "<cmd> @@@i", .arg_str = "", .comment = "run <cmd> on each import" },
{ .text = "<cmd> @@@r", .arg_str = "", .comment = "run <cmd> on each register" },
{ .text = "<cmd> @@@s", .arg_str = "", .comment = "run <cmd> on each symbol" },
{ .text = "<cmd> @@@st", .arg_str = "", .comment = "run <cmd> on each string" },
{ .text = "<cmd> @@@S", .arg_str = "", .comment = "run <cmd> on each section" },
{ .text = "<cmd> @@@m", .arg_str = "", .comment = "run <cmd> on each io.maps" },
{ .text = "<cmd> @@@M", .arg_str = "", .comment = "run <cmd> on each dbg.maps" },
{ .text = "<cmd> @@@f", .arg_str = "", .comment = "run <cmd> on each flag" },
{ .text = "<cmd> @@@f:", .arg_str = "<glob-string>", .comment = "run <cmd> on each flag matching <glob-string>. <glob-string> may contain `*` to indicate multiple chars" },
{ .text = "<cmd> @@@F", .arg_str = "", .comment = "run <cmd> on each function" },
{ .text = "<cmd> @@@F:", .arg_str = "<glob-string>", .comment = "run <cmd> on each function whose name matches <glob-string>. <glob-string> may contain `*` to indicate multiple chars" },
{ .text = "<cmd> @@@t", .arg_str = "", .comment = "run <cmd> on each thread" },
{ 0 },
};
const RzCmdDescDetail foreach_detail[] = {
{ .name = "", .entries = foreach_detail_entries },
{ 0 },
};
const RzCmdDescHelp foreach_help = {
.summary = "'@@@' help",
.options = "?",
.details = foreach_detail,
.usage = "<cmd> <@@@>",
};
const RzCmdDescDetailEntry redirection_detail_entries[] = {
{ .text = "<cmd> >", .arg_str = " <file>|<$alias>", .comment = "redirect STDOUT of <cmd> to <file> or save it to an alias (see $?)" },
{ .text = "<cmd> 2>", .arg_str = " <file>|<$alias>", .comment = "redirect STDERR of <cmd> to <file> or save it to an alias (see $?)" },
{ .text = "<cmd> H>", .arg_str = " <file>|<$alias>", .comment = "redirect HTML output of <cmd> to <file> or save it to an alias (see $?)" },
{ 0 },
};
const RzCmdDescDetail redirection_detail[] = {
{ .name = "", .entries = redirection_detail_entries },
{ 0 },
};
const RzCmdDescHelp redirection_help = {
.summary = "redirection help ('>')",
.options = "?",
.details = redirection_detail,
.usage = "<cmd> > <arg>",
};
const RzCmdDescDetailEntry pipe_detail_entries[] = {
{ .text = "<cmd> |", .arg_str = NULL, .comment = "disable scr.html and scr.color" },
{ .text = "<cmd> |H", .arg_str = NULL, .comment = "enable scr.html, respect scr.color" },
{ .text = "<cmd> |T", .arg_str = NULL, .comment = "use scr.tts to speak out the stdout" },
{ .text = "<cmd> |", .arg_str = " <program>", .comment = "pipe output of command to program" },
{ .text = "<cmd> |.", .arg_str = NULL, .comment = "alias for .<cmd>" },
{ 0 },
};
const RzCmdDescDetail pipe_detail[] = {
{ .name = "", .entries = pipe_detail_entries },
{ 0 },
};
const RzCmdDescHelp pipe_help = {
.summary = "pipe help ('|')",
.options = "?",
.details = pipe_detail,
.usage = "<cmd> |[<program>|H|T|.|]",
};
const RzCmdDescDetailEntry grep_modifiers[] = {
{ .text = "&", .arg_str = NULL, .comment = "all words must match to grep the line" },
{ .text = "$[n]", .arg_str = NULL, .comment = "sort numerically / alphabetically the Nth column" },
{ .text = "$!", .arg_str = NULL, .comment = "sort in inverse order" },
{ .text = ",", .arg_str = NULL, .comment = "token to define another keyword" },
{ .text = "+", .arg_str = NULL, .comment = "case insensitive grep (grep -i)" },
{ .text = "^", .arg_str = NULL, .comment = "words must be placed at the beginning of line" },
{ .text = "<", .arg_str = NULL, .comment = "perform zoom operation on the buffer" },
{ .text = "!", .arg_str = NULL, .comment = "negate grep" },
{ .text = "?", .arg_str = NULL, .comment = "count number of matching lines" },
{ .text = "?.", .arg_str = NULL, .comment = "count number chars" },
{ .text = ":s..e", .arg_str = NULL, .comment = "show lines s-e" },
{ .text = "..", .arg_str = NULL, .comment = "internal 'less'" },
{ .text = "...", .arg_str = NULL, .comment = "internal 'hud' (like V_)" },
{ .text = "{:", .arg_str = NULL, .comment = "human friendly indentation (yes, it's a smiley)" },
{ .text = "{:..", .arg_str = NULL, .comment = "less the output of {:" },
{ .text = "{:...", .arg_str = NULL, .comment = "hud the output of {:" },
{ .text = "{}", .arg_str = NULL, .comment = "json indentation" },
{ .text = "{}..", .arg_str = NULL, .comment = "less json indentation" },
{ .text = "{}...", .arg_str = NULL, .comment = "hud json indentation" },
{ .text = "{path}", .arg_str = NULL, .comment = "json path grep" },
{ 0 },
};
const RzCmdDescDetailEntry grep_endmodifiers[] = {
{ .text = "$", .arg_str = NULL, .comment = "words must be placed at the end of line" },
{ 0 },
};
const RzCmdDescDetailEntry grep_columns[] = {
{ .text = "[n]", .arg_str = NULL, .comment = "show only column n" },
{ .text = "[n-m]", .arg_str = NULL, .comment = "show column n to m" },
{ .text = "[n-]", .arg_str = NULL, .comment = "show all columns starting from column n" },
{ .text = "[i,j,k]", .arg_str = NULL, .comment = "show the columns i, j and k" },
{ 0 },
};
const RzCmdDescDetailEntry grep_examples[] = {
{ .text = "i", .arg_str = "~:0", .comment = "show first line of 'i' output" },
{ .text = "i", .arg_str = "~:-2", .comment = "show the second to last line of 'i' output" },
{ .text = "i", .arg_str = "~:0..3", .comment = "show first three lines of 'i' output" },
{ .text = "pd", .arg_str = "~mov", .comment = "disasm and grep for mov" },
{ .text = "pi", .arg_str = "~[0]", .comment = "show only opcode" },
{ .text = "i", .arg_str = "~0x400$", .comment = "show lines ending with 0x400" },
{ 0 },
};
const RzCmdDescDetail grep_detail[] = {
{ .name = "Modifiers", .entries = grep_modifiers },
{ .name = "EndModifiers", .entries = grep_endmodifiers },
{ .name = "Columns", .entries = grep_columns },
{ .name = "Examples", .entries = grep_examples },
{ 0 },
};
const RzCmdDescHelp grep_help = {
.summary = "grep help ('~')",
.options = "?",
.details = grep_detail,
.usage = "<command>~[modifier][word,word][endmodifier][[column]][:line]",
};
const RzCmdDescHelp system_help = {
.summary = "run given command as in system(3)",
};
@ -19,9 +216,9 @@ const RzCmdDescHelp alias_help = {
const RzCmdDescDetailEntry env_help_examples[] = {
{ .text = "%", .comment = "list all environment variables" },
{ .text = "%SHELL", .comment = "print value of SHELL variable" },
{ .text = "%TMPDIR=/tmp", .comment = "set TMPDIR to \"/tmp\"" },
{ .text = "env SHELL", .comment = "same as `%SHELL`" },
{ .text = "%", .arg_str = "SHELL", .comment = "print value of SHELL variable" },
{ .text = "%", .arg_str = "TMPDIR=/tmp", .comment = "set TMPDIR to \"/tmp\"" },
{ .text = "env", .arg_str = "SHELL", .comment = "same as `%SHELL`" },
{ 0 },
};
@ -71,9 +268,9 @@ const RzCmdDescHelp macro_help = {
};
const RzCmdDescDetailEntry pointer_help_examples[] = {
{ .text = "*entry0=cc", .comment = "write trap in entrypoint" },
{ .text = "*entry0+10=0x804800", .comment = "write 0x804800 as a 4-byte value at 10 bytes from the entrypoint" },
{ .text = "*entry0", .comment = "read the value contained at the entrypoint" },
{ .text = "*", .arg_str = "entry0=cc", .comment = "write trap in entrypoint" },
{ .text = "*", .arg_str = "entry0+10=0x804800", .comment = "write 0x804800 as a 4-byte value at 10 bytes from the entrypoint" },
{ .text = "*", .arg_str = "entry0", .comment = "read the value contained at the entrypoint" },
{ 0 },
};
@ -107,6 +304,7 @@ const RzCmdDescHelp rap_help = {
const RzCmdDescHelp help_help = {
.summary = "Help or evaluate math expression",
.options = "[??]",
};
const RzCmdDescHelp rap_run_help = {
@ -267,8 +465,8 @@ const RzCmdDescHelp w0_help = {
const RzCmdDescDetailEntry w_incdec_help_examples[] = {
{ .text = "w1+", .comment = "Add 1 to the byte at the current offset." },
{ .text = "w2-", .comment = "Subtract 1 to the word at the current offset." },
{ .text = "w4+ 0xdeadbeef", .comment = "Add 0xdeadbeef to the dword at the current offset." },
{ .text = "w8- 10", .comment = "Subtract 10 to the qword at the current offset." },
{ .text = "w4+", .arg_str = " 0xdeadbeef", .comment = "Add 0xdeadbeef to the dword at the current offset." },
{ .text = "w8-", .arg_str = " 10", .comment = "Subtract 10 to the qword at the current offset." },
{ 0 },
};
@ -374,7 +572,7 @@ const RzCmdDescHelp w8_dec_help = {
// wB helps
const RzCmdDescDetailEntry wB_help_examples[] = {
{ .text = "wB 0x20", .comment = "Sets the 5th bit at current offset, leaving all other bits intact." },
{ .text = "wB", .arg_str = " 0x20", .comment = "Sets the 5th bit at current offset, leaving all other bits intact." },
{ 0 },
};
@ -404,7 +602,7 @@ const RzCmdDescHelp wB_minus_help = {
// wv helps
const RzCmdDescDetailEntry wv_help_examples[] = {
{ .text = "wv 0xdeadbeef", .comment = "Write the value 0xdeadbeef at current offset" },
{ .text = "wv", .arg_str = " 0xdeadbeef", .comment = "Write the value 0xdeadbeef at current offset" },
{ 0 },
};
@ -447,8 +645,8 @@ const RzCmdDescHelp wv8_help = {
};
const RzCmdDescDetailEntry w6_help_examples[] = {
{ .text = "w6d SGVsbG9Xb3JsZAo=", .comment = "Write the string \"HelloWorld\" (without quotes) at current offset." },
{ .text = "w6e 48656c6c6f576f726c64", .comment = "Write the string \"SGVsbG9Xb3JsZAo=\" (without quotes) at current offset." },
{ .text = "w6d", .arg_str = " SGVsbG9Xb3JsZAo=", .comment = "Write the string \"HelloWorld\" (without quotes) at current offset." },
{ .text = "w6e", .arg_str = " 48656c6c6f576f726c64", .comment = "Write the string \"SGVsbG9Xb3JsZAo=\" (without quotes) at current offset." },
{ 0 },
};

View file

@ -3,6 +3,13 @@
#include <rz_cmd.h>
extern const RzCmdDescHelp tmp_modifier_help;
extern const RzCmdDescHelp iterator_help;
extern const RzCmdDescHelp foreach_help;
extern const RzCmdDescHelp redirection_help;
extern const RzCmdDescHelp pipe_help;
extern const RzCmdDescHelp grep_help;
extern const RzCmdDescHelp system_help;
extern const RzCmdDescHelp underscore_help;
extern const RzCmdDescHelp hash_help;

View file

@ -75,9 +75,30 @@ typedef struct rz_cmd_alias_t {
int *remote;
} RzCmdAlias;
/**
* A detailed entry that can be used to show additional info about a command entry.
* It can contain whatever relevant information (e.g. examples, specific uses of
* a command, variables, etc.).
*
* Displayed as:
* | <text><arg_str> # <comment>
*/
typedef struct rz_cmd_desc_detail_entry_t {
/**
* Main text of the detailed entry
*/
const char *text;
/**
* Short explanation of the entry, shown with the comment color
*/
const char *comment;
/**
* Text to show in a different color, after `text`, usually used to show
* arguments for examples.
*
* Optional.
*/
const char *arg_str;
} RzCmdDescDetailEntry;
/**
@ -164,6 +185,12 @@ typedef enum {
// stored in the hashtable and cannot be retrieved except by listing the
// children of its parent. Most of the time you want RZ_CMD_DESC_TYPE_GROUP.
RZ_CMD_DESC_TYPE_INNER,
// for entries that shall be shown in the help tree but that are not
// commands on their own. `|?`, `@?`, `>?` are example of this. It is
// useful to provide help entries for them in the tree, but there are no
// command handlers for these. The RzCmdDescDetail in the help can be
// used to show fake children of this descriptor.
RZ_CMD_DESC_TYPE_FAKE,
} RzCmdDescType;
typedef struct rz_cmd_desc_t {
@ -293,6 +320,7 @@ RZ_API RzCmdDesc *rz_cmd_desc_argv_new(RzCmd *cmd, RzCmdDesc *parent, const char
RZ_API RzCmdDesc *rz_cmd_desc_inner_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_group_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, RzCmdArgvCb cb, const RzCmdDescHelp *help, const RzCmdDescHelp *group_help);
RZ_API RzCmdDesc *rz_cmd_desc_oldinput_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, RzCmdCb cb, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_fake_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_parent(RzCmdDesc *cd);
RZ_API bool rz_cmd_desc_has_handler(RzCmdDesc *cd);
RZ_API bool rz_cmd_desc_remove(RzCmd *cmd, RzCmdDesc *cd);

View file

@ -5,8 +5,8 @@ CMDS=<<EOF
@@@?~?
EOF
EXPECT=<<EOF
16
18
15
17
EOF
RUN