diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 2c2e5e42d0..e3a4d848b3 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -112,11 +112,6 @@ jobs: export PATH=${HOME}/Library/Python/3.8/bin:${HOME}/Library/Python/3.9/bin:${HOME}/.local/bin:${PATH} find . -name "*.py" | grep -v "subprojects" | xargs black --check - - name: Run isort - run: | - export PATH=${HOME}/Library/Python/3.8/bin:${HOME}/Library/Python/3.9/bin:${HOME}/.local/bin:${PATH} - find . -name "*.py" | grep -v "subprojects" | xargs isort --check - - name: Run pylint run: | export PATH=${HOME}/Library/Python/3.8/bin:${HOME}/Library/Python/3.9/bin:${HOME}/.local/bin:${PATH} diff --git a/doc/rzshell.md b/doc/rzshell.md index 270b6b6da5..0a5a6b552e 100644 --- a/doc/rzshell.md +++ b/doc/rzshell.md @@ -138,13 +138,16 @@ files: `cmd_descs.c` and `cmd_descs.h`. ## Where is the handler of command `x`? -If you are looking for the handler of command `x`, you just have to look at -the file +You can use the script `librz/core/cmd_descs/rzshell_find_handler.py` to get the +name of the function handling the specified command. + +If that doesn't work, please report the problem to us! However, you can still +find the handler yourself by looking at the file [`librz/core/cmd_descs.yaml`](https://github.com/rizinorg/rizin/blob/9ce5003ca647cdfc181ac3c0f6206762ebb9e3e9/librz/core/cmd_descs.yaml). -By looking at the `cname` field of the command descriptor, you can see what -is the name of the handler of the `x` command. If the `cname` is `hex` and -the type is `RZ_CMD_DESC_TYPE_OLDINPUT`, then the handler will be named -`rz_hex`. In all other cases, the handler will be named `rz_hex_handler`. +By looking at the `cname` field of the command descriptor, you can see what is +the name of the handler of the `x` command. If the `cname` is `hex` and the type +is `RZ_CMD_DESC_TYPE_OLDINPUT`, then the handler will be named `rz_hex`. In all +other cases, the handler will be named `rz_hex_handler`. Some examples: - command: `wv`, type: unspecified (default to `RZ_CMD_DESC_TYPE_ARGV`), handler: `rz_write_value_handler` diff --git a/librz/core/cmd_descs/cmd_descs_generate.py b/librz/core/cmd_descs/cmd_descs_generate.py index a2eb696ca2..db2c95b8c3 100755 --- a/librz/core/cmd_descs/cmd_descs_generate.py +++ b/librz/core/cmd_descs/cmd_descs_generate.py @@ -7,6 +7,19 @@ import os import sys import yaml +from cmd_descs_util import ( + CD_ARG_LAST_TYPES, + CD_TYPE_ARGV, + CD_TYPE_ARGV_MODES, + CD_TYPE_ARGV_STATE, + CD_TYPE_FAKE, + CD_TYPE_GROUP, + CD_TYPE_INNER, + CD_TYPE_OLDINPUT, + CD_VALID_TYPES, + compute_cname, + get_handler_cname, +) CMDDESCS_C_TEMPLATE = """// SPDX-FileCopyrightText: 2021 RizinOrg // SPDX-License-Identifier: LGPL-3.0-only @@ -120,88 +133,19 @@ DEFINE_FAKE_TEMPLATE = """ SET_DEFAULT_MODE_TEMPLATE = """ \trz_cmd_desc_set_default_mode({cname}_cd, {default_mode});""" -CD_TYPE_OLDINPUT = "RZ_CMD_DESC_TYPE_OLDINPUT" -CD_TYPE_GROUP = "RZ_CMD_DESC_TYPE_GROUP" -CD_TYPE_ARGV = "RZ_CMD_DESC_TYPE_ARGV" -CD_TYPE_ARGV_MODES = "RZ_CMD_DESC_TYPE_ARGV_MODES" -CD_TYPE_ARGV_STATE = "RZ_CMD_DESC_TYPE_ARGV_STATE" -CD_TYPE_FAKE = "RZ_CMD_DESC_TYPE_FAKE" -CD_TYPE_INNER = "RZ_CMD_DESC_TYPE_INNER" -CD_VALID_TYPES = [ - CD_TYPE_OLDINPUT, - CD_TYPE_GROUP, - CD_TYPE_ARGV, - CD_TYPE_ARGV_MODES, - CD_TYPE_ARGV_STATE, - CD_TYPE_FAKE, - CD_TYPE_INNER, -] - -CD_ARG_LAST_TYPES = [ - "RZ_CMD_ARG_TYPE_RZNUM", - "RZ_CMD_ARG_TYPE_STRING", - "RZ_CMD_ARG_TYPE_CMD", -] - - -def escape(s): +def _escape(s): return s.replace("\\", "\\\\").replace('"', '\\"') def strornull(s): - return '"' + escape(s) + '"' if s is not None else "NULL" + return '"' + _escape(s) + '"' if s is not None else "NULL" def strip(s): return s.strip("\n") if s is not None else None -def compute_cname(name): - if name == "": - return "empty" - - name = name.translate( - str.maketrans( - { - ".": "_dot_", - "*": "_star_", - ">": "_greater_", - "<": "_minor_", - "-": "_minus_", - "+": "_plus_", - "=": "_equal_", - "$": "_dollar_", - "?": "_question_", - "/": "_slash_", - "\\": "_backslash_", - "&": "_and_", - "!": "_escl_", - "#": "_hash_", - " ": "_space_", - "(": "_oparen_", - ")": "_cparen_", - } - ) - ) - if name.startswith("_"): - name = name[1:] - - return name - - -def flat(l): - if l is None: - return [] - if not isinstance(l, list): - return [l] - - out = [] - for i in l: - out += flat(i) - return out - - class Arg: def __init__(self, cd, c): if "name" not in c or "type" not in c: @@ -512,13 +456,14 @@ class CmdDesc: sys.exit(1) def get_handler_cname(self): - if self.type in [CD_TYPE_ARGV, CD_TYPE_ARGV_MODES, CD_TYPE_ARGV_STATE]: - return "rz_" + (self.handler or self.cname) + "_handler" - - if self.type == CD_TYPE_OLDINPUT: - return "rz_" + (self.handler or self.cname) - - return None + if self.type not in [ + CD_TYPE_OLDINPUT, + CD_TYPE_ARGV, + CD_TYPE_ARGV_MODES, + CD_TYPE_ARGV_STATE, + ]: + return None + return get_handler_cname(self.type, self.handler, self.cname) @classmethod def get_arg_cname(cls, cd): diff --git a/librz/core/cmd_descs/cmd_descs_util.py b/librz/core/cmd_descs/cmd_descs_util.py new file mode 100644 index 0000000000..4dcc463ccf --- /dev/null +++ b/librz/core/cmd_descs/cmd_descs_util.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2020-2021 ret2libc +# SPDX-License-Identifier: LGPL-3.0-only + +CD_TYPE_OLDINPUT = "RZ_CMD_DESC_TYPE_OLDINPUT" +CD_TYPE_GROUP = "RZ_CMD_DESC_TYPE_GROUP" +CD_TYPE_ARGV = "RZ_CMD_DESC_TYPE_ARGV" +CD_TYPE_ARGV_MODES = "RZ_CMD_DESC_TYPE_ARGV_MODES" +CD_TYPE_ARGV_STATE = "RZ_CMD_DESC_TYPE_ARGV_STATE" +CD_TYPE_FAKE = "RZ_CMD_DESC_TYPE_FAKE" +CD_TYPE_INNER = "RZ_CMD_DESC_TYPE_INNER" + +CD_VALID_TYPES = [ + CD_TYPE_OLDINPUT, + CD_TYPE_GROUP, + CD_TYPE_ARGV, + CD_TYPE_ARGV_MODES, + CD_TYPE_ARGV_STATE, + CD_TYPE_FAKE, + CD_TYPE_INNER, +] + +CD_ARG_LAST_TYPES = [ + "RZ_CMD_ARG_TYPE_RZNUM", + "RZ_CMD_ARG_TYPE_STRING", + "RZ_CMD_ARG_TYPE_CMD", +] + + +def compute_cname(name): + if name == "": + return "empty" + + name = name.translate( + str.maketrans( + { + ".": "_dot_", + "*": "_star_", + ">": "_greater_", + "<": "_minor_", + "-": "_minus_", + "+": "_plus_", + "=": "_equal_", + "$": "_dollar_", + "?": "_question_", + "/": "_slash_", + "\\": "_backslash_", + "&": "_and_", + "!": "_escl_", + "#": "_hash_", + " ": "_space_", + "(": "_oparen_", + ")": "_cparen_", + } + ) + ) + if name.startswith("_"): + name = name[1:] + + return name + + +def get_handler_cname(ty, handler, cname): + if ty == CD_TYPE_OLDINPUT: + return "rz_" + (handler or cname) + + return "rz_" + (handler or cname) + "_handler" diff --git a/librz/core/cmd_descs/rzshell_which.py b/librz/core/cmd_descs/rzshell_which.py new file mode 100755 index 0000000000..28a4badcfe --- /dev/null +++ b/librz/core/cmd_descs/rzshell_which.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2021 ret2libc +# SPDX-License-Identifier: LGPL-3.0-only + +import argparse +import glob +import os +import sys + +import yaml +from cmd_descs_util import CD_TYPE_OLDINPUT, compute_cname, get_handler_cname + + +def get_yaml_files(basedir): + for file in glob.glob(os.path.join(basedir, "*.yaml")): + yield file + + +def find_entry(commands, rzcommand): + for c in commands: + if "subcommands" in c and isinstance(c["subcommands"], list): + e = find_entry(c["subcommands"], rzcommand) + if e is not None: + return e + + if c["name"] == rzcommand: + return c + + return None + + +def get_c_handler_name_from_entry(e): + name = e["cname"] + if "handler" in e and e["handler"]: + name = e["handler"] + + if "type" in e and e["type"] == CD_TYPE_OLDINPUT: + return f"rz_{name}" + + return f"rz_{name}_handler" + + +def find_c_name_handler(basedir, rzcommand): + for f in get_yaml_files(basedir): + with open(f, "r", encoding="utf8") as of: + y = yaml.safe_load(of) + e = find_entry(y["commands"], rzcommand) + if e is not None: + cname = e.get("cname", compute_cname(e["name"])) + return get_handler_cname( + e.get("type", None), e.get("handler", None), cname + ) + + return None + + +def main(): + parser = argparse.ArgumentParser( + description="Find the C handler of a rizin command" + ) + parser.add_argument( + "--cmddescs-dir", + default=os.path.join("librz", "core", "cmd_descs"), + type=str, + help="Path to the cmd_descs directory containing the *.yaml files", + ) + parser.add_argument("rzcommand", type=str, help="Name of the rizin command") + + args = parser.parse_args() + c_name = find_c_name_handler(args.cmddescs_dir, args.rzcommand) + if c_name is None: + print( + f"Command {args.rzcommand} does not exist or it is not converted to rzshell yet." + ) + sys.exit(1) + + CRED = "\033[91m" + CEND = "\033[0m" + + print(f"Rizin Command: {CRED}{args.rzcommand}{CEND}") + print(f"C handler: {CRED}{c_name}{CEND}") + print( + f'Git command to get it: {CRED}git grep -nWG "^[^[:blank:]].*{c_name}(" *.c{CEND}' + ) + + +if __name__ == "__main__": + main() diff --git a/sys/rzshell_which.py b/sys/rzshell_which.py new file mode 100755 index 0000000000..2d988484b8 --- /dev/null +++ b/sys/rzshell_which.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2021 ret2libc +# SPDX-License-Identifier: LGPL-3.0-only + +import os +import subprocess +import sys + +current_path = os.path.dirname(os.path.realpath(__file__)) +shell_finder_py = os.path.join( + current_path, "..", "librz", "core", "cmd_descs", "rzshell_which.py" +) + +subprocess.run([shell_finder_py] + sys.argv[1:], check=False)