xref: /llvm-project/lldb/test/API/commands/command/script/add/test_commands.py (revision 04b443e77845cd20ab5acc4356cee509316135dd)
1"""
2Test defining commands using the lldb command definitions
3"""
4import inspect
5import sys
6import lldb
7from lldb.plugins.parsed_cmd import ParsedCommand
8
9
10class ReportingCmd(ParsedCommand):
11    def __init__(self, debugger, unused):
12        super().__init__(debugger, unused)
13
14    def __call__(self, debugger, args_array, exe_ctx, result):
15        opt_def = self.get_options_definition()
16        if len(opt_def):
17            result.AppendMessage("Options:\n")
18            for long_option, elem in opt_def.items():
19                dest = elem["dest"]
20                result.AppendMessage(
21                    f"{long_option} (set: {elem['_value_set']}): {object.__getattribute__(self.get_parser(), dest)}\n"
22                )
23        else:
24            result.AppendMessage("No options\n")
25
26        num_args = args_array.GetSize()
27        if num_args > 0:
28            result.AppendMessage(f"{num_args} arguments:")
29        for idx in range(0, num_args):
30            result.AppendMessage(
31                f"{idx}: {args_array.GetItemAtIndex(idx).GetStringValue(10000)}\n"
32            )
33
34# Use these to make sure that get_repeat_command sends the right
35# command.
36no_args_repeat = None
37one_arg_repeat = None
38two_arg_repeat = None
39
40class NoArgsCommand(ReportingCmd):
41    program = "no-args"
42
43    def __init__(self, debugger, unused):
44        super().__init__(debugger, unused)
45
46    @classmethod
47    def register_lldb_command(cls, debugger, module_name):
48        ParsedCommand.do_register_cmd(cls, debugger, module_name)
49
50    def setup_command_definition(self):
51        ov_parser = self.get_parser()
52        ov_parser.add_option(
53            "b",
54            "bool-arg",
55            "a boolean arg, defaults to True",
56            value_type=lldb.eArgTypeBoolean,
57            groups=[1, 2],
58            dest="bool_arg",
59            default=True,
60        )
61
62        ov_parser.add_option(
63            "s",
64            "shlib-name",
65            "A shared library name.",
66            value_type=lldb.eArgTypeShlibName,
67            groups=[1, [3, 4]],
68            dest="shlib_name",
69            default=None,
70        )
71
72        ov_parser.add_option(
73            "d",
74            "disk-file-name",
75            "An on disk filename",
76            value_type=lldb.eArgTypeFilename,
77            dest="disk_file_name",
78            default=None,
79        )
80
81        ov_parser.add_option(
82            "l",
83            "line-num",
84            "A line number",
85            value_type=lldb.eArgTypeLineNum,
86            groups=3,
87            dest="line_num",
88            default=0,
89        )
90
91        ov_parser.add_option(
92            "e",
93            "enum-option",
94            "An enum, doesn't actually do anything",
95            enum_values=[
96                ["foo", "does foo things"],
97                ["bar", "does bar things"],
98                ["baz", "does baz things"],
99            ],
100            groups=4,
101            dest="enum_option",
102            default="foo",
103        )
104
105    def get_repeat_command(self, command):
106        # No auto-repeat
107        global no_args_repeat
108        no_args_repeat = command
109        return ""
110
111    def get_short_help(self):
112        return "Example command for use in debugging"
113
114    def get_long_help(self):
115        return self.help_string
116
117
118class OneArgCommandNoOptions(ReportingCmd):
119    program = "one-arg-no-opt"
120
121    def __init__(self, debugger, unused):
122        super().__init__(debugger, unused)
123
124    @classmethod
125    def register_lldb_command(cls, debugger, module_name):
126        ParsedCommand.do_register_cmd(cls, debugger, module_name)
127
128    def setup_command_definition(self):
129        ov_parser = self.get_parser()
130        ov_parser.add_argument_set(
131            [ov_parser.make_argument_element(lldb.eArgTypeSourceFile, "plain")]
132        )
133
134    def get_repeat_command(self, command):
135        # Repeat the current command
136        global one_arg_repeat
137        one_arg_repeat = command
138        return None
139
140    def get_short_help(self):
141        return "Example command for use in debugging"
142
143    def get_long_help(self):
144        return self.help_string
145
146
147class TwoArgGroupsCommand(ReportingCmd):
148    program = "two-args"
149
150    def __init__(self, debugger, unused):
151        super().__init__(debugger, unused)
152
153    @classmethod
154    def register_lldb_command(cls, debugger, module_name):
155        ParsedCommand.do_register_cmd(cls, debugger, module_name)
156
157    def setup_command_definition(self):
158        ov_parser = self.get_parser()
159        ov_parser.add_option(
160            "l",
161            "language",
162            "language defaults to None",
163            value_type=lldb.eArgTypeLanguage,
164            groups=[1, 2],
165            dest="language",
166            default=None,
167        )
168
169        ov_parser.add_option(
170            "c",
171            "log-channel",
172            "log channel - defaults to lldb",
173            value_type=lldb.eArgTypeLogChannel,
174            groups=[1, 3],
175            dest="log_channel",
176            default="lldb",
177        )
178
179        ov_parser.add_option(
180            "p",
181            "process-name",
182            "A process name, defaults to None",
183            value_type=lldb.eArgTypeProcessName,
184            dest="proc_name",
185            default=None,
186        )
187
188        ov_parser.add_argument_set(
189            [
190                ov_parser.make_argument_element(
191                    lldb.eArgTypeClassName, "plain", [1, 2]
192                ),
193                ov_parser.make_argument_element(
194                    lldb.eArgTypeOffset, "optional", [1, 2]
195                ),
196            ]
197        )
198
199        ov_parser.add_argument_set(
200            [
201                ov_parser.make_argument_element(
202                    lldb.eArgTypePythonClass, "plain", [3, 4]
203                ),
204                ov_parser.make_argument_element(lldb.eArgTypePid, "optional", [3, 4]),
205            ]
206        )
207
208    def get_repeat_command(self, command):
209        global two_arg_repeat
210        two_arg_repeat = command
211        return command + " THIRD_ARG"
212
213    def handle_option_argument_completion(self, long_option, cursor_pos):
214        ov_parser = self.get_parser()
215        value = ov_parser.dest_for_option(long_option)[0 : cursor_pos + 1]
216        proc_value = ov_parser.proc_name
217        if proc_value != None:
218            new_str = value + proc_value
219            ret_arr = {"completion": new_str, "mode": "partial"}
220            return ret_arr
221
222        ret_arr = {"values": [value + "nice", value + "not_nice", value + "mediocre"]}
223        return ret_arr
224
225    def handle_argument_completion(self, args, arg_pos, cursor_pos):
226        ov_parser = self.get_parser()
227        orig_arg = args[arg_pos][0:cursor_pos]
228        if orig_arg == "correct_":
229            ret_arr = {"completion": "correct_answer"}
230            return ret_arr
231
232        if ov_parser.was_set("process-name"):
233            # No completions if proc_name was set.
234            return True
235
236        ret_arr = {
237            "values": [orig_arg + "cool", orig_arg + "yuck"],
238            "descriptions": ["good idea", "bad idea"],
239        }
240        return ret_arr
241
242    def get_short_help(self):
243        return "This is my short help string"
244
245    def get_long_help(self):
246        return self.help_string
247
248
249def __lldb_init_module(debugger, dict):
250    # Register all classes that have a register_lldb_command method
251    for _name, cls in inspect.getmembers(sys.modules[__name__]):
252        if inspect.isclass(cls) and callable(
253            getattr(cls, "register_lldb_command", None)
254        ):
255            cls.register_lldb_command(debugger, __name__)
256