Skip to content

Commit 29e4490

Browse files
authored
Merge pull request #24 from p-x9/feature/refactor-command-definition
Refactor command definition
2 parents d704d88 + 54afd4f commit 29e4490

File tree

11 files changed

+693
-505
lines changed

11 files changed

+693
-505
lines changed

.vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
"flake8.args": ["--ignore=E226 E401 E402 E741", "--max-line-length=150"],
1010
"autopep8.args": ["--ignore=E402", "--max-line-length=150", "--aggressive"],
11-
"mypy-type-checker.args": ["--config-file=.mypy.ini"],
11+
"mypy-type-checker.args": ["--config-file=mypy.ini"],
1212
"mypy.configFile": "mypy.ini",
1313
"terminal.integrated.env.osx": {
1414
"PYTHONPATH": "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python"

src/LLDBHelper/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__all__ = ['LLDBCommandBase']
2+
3+
from lldbhelper.lldb_command_base import LLDBCommandBase

src/LLDBHelper/lldb_command_base.py

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import lldb
2+
from abc import ABC, abstractmethod
3+
import argparse
4+
5+
# ref: https://lldb.llvm.org/use/python-reference.html#create-a-new-lldb-command-using-a-python-function
6+
7+
8+
class LLDBCommandBase(ABC):
9+
"""
10+
Abstract base class for creating LLDB commands.
11+
12+
This class provides a framework for creating LLDB commands.
13+
It defines abstract methods for command name, description, argument parser creation, and command execution.
14+
It also provides methods for registering the command with LLDB and retrieving help information.
15+
"""
16+
17+
@classmethod
18+
@abstractmethod
19+
def cmdname(cls) -> str:
20+
"""
21+
Abstract method that returns the name of the command.
22+
23+
Returns:
24+
str: The name of the command.
25+
"""
26+
pass
27+
28+
@classmethod
29+
@abstractmethod
30+
def description(cls) -> str:
31+
"""
32+
Abstract method that returns the description of the command.
33+
34+
Returns:
35+
str: The description of the command.
36+
"""
37+
pass
38+
39+
@classmethod
40+
def register_lldb_command(cls, debugger: lldb.SBDebugger, module_name: str) -> None:
41+
"""
42+
Registers the command with LLDB.
43+
44+
This method sets the command's description and adds it to the debugger.
45+
46+
Args:
47+
debugger (lldb.SBDebugger): The LLDB debugger.
48+
module_name (str): The name of the module.
49+
50+
Returns:
51+
None
52+
"""
53+
cls.__doc__ = cls.description()
54+
55+
command = f"command script add -o -c {module_name}.{cls.__name__} {cls.cmdname()}"
56+
debugger.HandleCommand(command)
57+
58+
@abstractmethod
59+
def create_argparser(self) -> argparse.ArgumentParser:
60+
"""
61+
Abstract method that creates and returns an argument parser for the command.
62+
63+
Returns:
64+
argparse.ArgumentParser: The argument parser for the command.
65+
"""
66+
pass
67+
68+
def __init__(self, debugger: lldb.SBDebugger, internal_dict: dict):
69+
"""
70+
Initializes the LLDBCommandBase instance.
71+
72+
Args:
73+
debugger (lldb.SBDebugger): The LLDB debugger.
74+
internal_dict (dict): The internal dictionary.
75+
76+
Returns:
77+
None
78+
"""
79+
self.argparser = self.create_argparser()
80+
81+
@abstractmethod
82+
def __call__(
83+
self,
84+
debugger: lldb.SBDebugger,
85+
command: str,
86+
exe_ctx: lldb.SBExecutionContext,
87+
result: lldb.SBCommandReturnObject
88+
) -> None:
89+
"""
90+
Abstract method that executes the command logic.
91+
92+
Args:
93+
debugger (lldb.SBDebugger): The LLDB debugger.
94+
command (str): The command string.
95+
exe_ctx (lldb.SBExecutionContext): The execution context.
96+
result (lldb.SBCommandReturnObject): The command result.
97+
98+
Returns:
99+
None
100+
"""
101+
pass
102+
103+
def get_short_help(self) -> str:
104+
"""
105+
Returns the short help message for the command.
106+
Default implementation is that `description` is returned.
107+
108+
Returns:
109+
str: The short help message.
110+
"""
111+
return self.description()
112+
113+
def get_long_help(self) -> str:
114+
"""
115+
Returns the long help message for the command.
116+
Default implementation is that the argparser help message is returned.
117+
118+
Returns:
119+
str: The long help message.
120+
"""
121+
return self.argparser.format_help()

src/app.py

+47-33
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,62 @@
22
import shlex
33
import argparse
44
from typing import Union, cast
5+
from lldbhelper import LLDBCommandBase
56
import util
67

78

89
def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict: dict) -> None:
9-
debugger.HandleCommand('command script add -f app.handle_command app -h "Application debugging. [iLLDB]"')
10+
AppCommnad.register_lldb_command(debugger, AppCommnad.__module__)
1011

1112

12-
def handle_command(
13-
debugger: lldb.SBDebugger,
14-
command: str,
15-
exe_ctx: lldb.SBExecutionContext,
16-
result: lldb.SBCommandReturnObject,
17-
internal_dict: dict) -> None:
18-
parser = create_argparser()
19-
args: Union[list[str], argparse.Namespace] = shlex.split(command, posix=False)
20-
args = parser.parse_args(cast(list[str], args))
21-
22-
if args.subcommand == "info":
23-
info(args, debugger, result)
24-
else:
25-
parser.print_help()
26-
13+
class AppCommnad(LLDBCommandBase):
2714

28-
def create_argparser() -> argparse.ArgumentParser:
29-
parser = argparse.ArgumentParser(description="App debugging",
30-
formatter_class=util.HelpFormatter)
31-
subparsers = parser.add_subparsers(title="Subcommands", dest="subcommand")
15+
@classmethod
16+
def cmdname(cls) -> str:
17+
return 'app'
3218

33-
subparsers.add_parser("info",
34-
help="Show App info",
35-
formatter_class=util.HelpFormatter)
19+
@classmethod
20+
def description(cls) -> str:
21+
return 'Application debugging. [iLLDB]'
3622

37-
return parser
23+
def create_argparser(self) -> argparse.ArgumentParser:
24+
parser = argparse.ArgumentParser(description="App debugging",
25+
formatter_class=util.HelpFormatter)
26+
subparsers = parser.add_subparsers(title="Subcommands", dest="subcommand")
3827

28+
subparsers.add_parser("info",
29+
help="Show App info",
30+
formatter_class=util.HelpFormatter)
3931

40-
def info(args: argparse.Namespace, debugger: lldb.SBDebugger, result: lldb.SBCommandReturnObject) -> None:
41-
script = util.read_script_file('swift/app.swift')
42-
script += """
43-
printAppInfo()
44-
"""
32+
return parser
4533

46-
_ = util.exp_script(
47-
debugger,
48-
script
49-
)
34+
def __call__(
35+
self,
36+
debugger: lldb.SBDebugger,
37+
command: str,
38+
exe_ctx: lldb.SBExecutionContext,
39+
result: lldb.SBCommandReturnObject
40+
) -> None:
41+
args: Union[list[str], argparse.Namespace] = shlex.split(command, posix=False)
42+
args = self.argparser.parse_args(cast(list[str], args))
43+
44+
if args.subcommand == "info":
45+
self.info(args, debugger, result)
46+
else:
47+
self.argparser.print_help()
48+
49+
def info(
50+
self,
51+
args: argparse.Namespace,
52+
debugger: lldb.SBDebugger,
53+
result: lldb.SBCommandReturnObject
54+
) -> None:
55+
script = util.read_script_file('swift/app.swift')
56+
script += """
57+
printAppInfo()
58+
"""
59+
60+
_ = util.exp_script(
61+
debugger,
62+
script
63+
)

0 commit comments

Comments
 (0)