xref: /llvm-project/mlir/utils/lldb-scripts/action_debugging.py (revision 1020150e7a6f6d6f833c232125c5ab817c03c76b)
1*1020150eSMehdi Amini#!/usr/bin/env python
2*1020150eSMehdi Amini
3*1020150eSMehdi Amini# ---------------------------------------------------------------------
4*1020150eSMehdi Amini# Be sure to add the python path that points to the LLDB shared library.
5*1020150eSMehdi Amini#
6*1020150eSMehdi Amini# # To use this in the embedded python interpreter using "lldb" just
7*1020150eSMehdi Amini# import it with the full path using the "command script import"
8*1020150eSMehdi Amini# command
9*1020150eSMehdi Amini#   (lldb) command script import /path/to/cmdtemplate.py
10*1020150eSMehdi Amini# ---------------------------------------------------------------------
11*1020150eSMehdi Amini
12*1020150eSMehdi Aminiimport inspect
13*1020150eSMehdi Aminiimport lldb
14*1020150eSMehdi Aminiimport argparse
15*1020150eSMehdi Aminiimport shlex
16*1020150eSMehdi Aminiimport sys
17*1020150eSMehdi Amini
18*1020150eSMehdi Amini# Each new breakpoint gets a unique ID starting from 1.
19*1020150eSMehdi Amininextid = 1
20*1020150eSMehdi Amini# List of breakpoint set from python, the key is the ID and the value the
21*1020150eSMehdi Amini# actual breakpoint. These are NOT LLDB SBBreakpoint objects.
22*1020150eSMehdi Aminibreakpoints = dict()
23*1020150eSMehdi Amini
24*1020150eSMehdi AminiexprOptions = lldb.SBExpressionOptions()
25*1020150eSMehdi AminiexprOptions.SetIgnoreBreakpoints()
26*1020150eSMehdi AminiexprOptions.SetLanguage(lldb.eLanguageTypeC)
27*1020150eSMehdi Amini
28*1020150eSMehdi Amini
29*1020150eSMehdi Aminiclass MlirDebug:
30*1020150eSMehdi Amini    """MLIR debugger commands
31*1020150eSMehdi Amini    This is the class that hooks into LLDB and registers the `mlir` command.
32*1020150eSMehdi Amini    Other providers can register subcommands below this one.
33*1020150eSMehdi Amini    """
34*1020150eSMehdi Amini
35*1020150eSMehdi Amini    lldb_command = "mlir"
36*1020150eSMehdi Amini    parser = None
37*1020150eSMehdi Amini
38*1020150eSMehdi Amini    def __init__(self, debugger, unused):
39*1020150eSMehdi Amini        super().__init__()
40*1020150eSMehdi Amini        self.create_options()
41*1020150eSMehdi Amini        self.help_string = MlirDebug.parser.format_help()
42*1020150eSMehdi Amini
43*1020150eSMehdi Amini    @classmethod
44*1020150eSMehdi Amini    def create_options(cls):
45*1020150eSMehdi Amini        if MlirDebug.parser:
46*1020150eSMehdi Amini            return MlirDebug.parser
47*1020150eSMehdi Amini        usage = "usage: %s [options]" % (cls.lldb_command)
48*1020150eSMehdi Amini        description = "TODO."
49*1020150eSMehdi Amini
50*1020150eSMehdi Amini        # Pass add_help_option = False, since this keeps the command in line
51*1020150eSMehdi Amini        # with lldb commands, and we wire up "help command" to work by
52*1020150eSMehdi Amini        # providing the long & short help methods below.
53*1020150eSMehdi Amini        MlirDebug.parser = argparse.ArgumentParser(
54*1020150eSMehdi Amini            prog=cls.lldb_command, usage=usage, description=description, add_help=False
55*1020150eSMehdi Amini        )
56*1020150eSMehdi Amini        MlirDebug.subparsers = MlirDebug.parser.add_subparsers(dest="command")
57*1020150eSMehdi Amini        return MlirDebug.parser
58*1020150eSMehdi Amini
59*1020150eSMehdi Amini    def get_short_help(self):
60*1020150eSMehdi Amini        return "MLIR debugger commands"
61*1020150eSMehdi Amini
62*1020150eSMehdi Amini    def get_long_help(self):
63*1020150eSMehdi Amini        return self.help_string
64*1020150eSMehdi Amini
65*1020150eSMehdi Amini    def __call__(self, debugger, command, exe_ctx, result):
66*1020150eSMehdi Amini        # Use the Shell Lexer to properly parse up command options just like a
67*1020150eSMehdi Amini        # shell would
68*1020150eSMehdi Amini        command_args = shlex.split(command)
69*1020150eSMehdi Amini
70*1020150eSMehdi Amini        try:
71*1020150eSMehdi Amini            args = MlirDebug.parser.parse_args(command_args)
72*1020150eSMehdi Amini        except:
73*1020150eSMehdi Amini            result.SetError("option parsing failed")
74*1020150eSMehdi Amini            raise
75*1020150eSMehdi Amini        args.func(args, debugger, command, exe_ctx, result)
76*1020150eSMehdi Amini
77*1020150eSMehdi Amini    @classmethod
78*1020150eSMehdi Amini    def on_process_start(frame, bp_loc, dict):
79*1020150eSMehdi Amini        print("Process started")
80*1020150eSMehdi Amini
81*1020150eSMehdi Amini
82*1020150eSMehdi Aminiclass SetControl:
83*1020150eSMehdi Amini    # Define the subcommands that controls what to do when a breakpoint is hit.
84*1020150eSMehdi Amini    # The key is the subcommand name, the value is a tuple of the command ID to
85*1020150eSMehdi Amini    # pass to MLIR and the help string.
86*1020150eSMehdi Amini    commands = {
87*1020150eSMehdi Amini        "apply": (1, "Apply the current action and continue the execution"),
88*1020150eSMehdi Amini        "skip": (2, "Skip the current action and continue the execution"),
89*1020150eSMehdi Amini        "step": (3, "Step into the current action"),
90*1020150eSMehdi Amini        "next": (4, "Step over the current action"),
91*1020150eSMehdi Amini        "finish": (5, "Step out of the current action"),
92*1020150eSMehdi Amini    }
93*1020150eSMehdi Amini
94*1020150eSMehdi Amini    @classmethod
95*1020150eSMehdi Amini    def register_mlir_subparser(cls):
96*1020150eSMehdi Amini        for cmd, (cmdInt, help) in cls.commands.items():
97*1020150eSMehdi Amini            parser = MlirDebug.subparsers.add_parser(
98*1020150eSMehdi Amini                cmd,
99*1020150eSMehdi Amini                help=help,
100*1020150eSMehdi Amini            )
101*1020150eSMehdi Amini            parser.set_defaults(func=cls.process_options)
102*1020150eSMehdi Amini
103*1020150eSMehdi Amini    @classmethod
104*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
105*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
106*1020150eSMehdi Amini        if not frame.IsValid():
107*1020150eSMehdi Amini            result.SetError("No valid frame (program not running?)")
108*1020150eSMehdi Amini            return
109*1020150eSMehdi Amini        cmdInt = cls.commands.get(options.command, None)
110*1020150eSMehdi Amini        if not cmdInt:
111*1020150eSMehdi Amini            result.SetError("Invalid command: %s" % (options.command))
112*1020150eSMehdi Amini            return
113*1020150eSMehdi Amini
114*1020150eSMehdi Amini        result = frame.EvaluateExpression(
115*1020150eSMehdi Amini            "((bool (*)(int))mlirDebuggerSetControl)(%d)" % (cmdInt[0]),
116*1020150eSMehdi Amini            exprOptions,
117*1020150eSMehdi Amini        )
118*1020150eSMehdi Amini        if not result.error.Success():
119*1020150eSMehdi Amini            print("Error setting up command: %s" % (result.error))
120*1020150eSMehdi Amini            return
121*1020150eSMehdi Amini        debugger.SetAsync(True)
122*1020150eSMehdi Amini        result = exe_ctx.GetProcess().Continue()
123*1020150eSMehdi Amini        debugger.SetAsync(False)
124*1020150eSMehdi Amini
125*1020150eSMehdi Amini
126*1020150eSMehdi Aminiclass PrintContext:
127*1020150eSMehdi Amini    @classmethod
128*1020150eSMehdi Amini    def register_mlir_subparser(cls):
129*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
130*1020150eSMehdi Amini            "context", help="Print the current context"
131*1020150eSMehdi Amini        )
132*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
133*1020150eSMehdi Amini
134*1020150eSMehdi Amini    @classmethod
135*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
136*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
137*1020150eSMehdi Amini        if not frame.IsValid():
138*1020150eSMehdi Amini            result.SetError("Can't print context without a valid frame")
139*1020150eSMehdi Amini            return
140*1020150eSMehdi Amini        result = frame.EvaluateExpression(
141*1020150eSMehdi Amini            "((bool (*)())&mlirDebuggerPrintContext)()", exprOptions
142*1020150eSMehdi Amini        )
143*1020150eSMehdi Amini        if not result.error.Success():
144*1020150eSMehdi Amini            print("Error printing context: %s" % (result.error))
145*1020150eSMehdi Amini            return
146*1020150eSMehdi Amini
147*1020150eSMehdi Amini
148*1020150eSMehdi Aminiclass Backtrace:
149*1020150eSMehdi Amini    @classmethod
150*1020150eSMehdi Amini    def register_mlir_subparser(cls):
151*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
152*1020150eSMehdi Amini            "backtrace", aliases=["bt"], help="Print the current backtrace"
153*1020150eSMehdi Amini        )
154*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
155*1020150eSMehdi Amini        cls.parser.add_argument("--context", default=False, action="store_true")
156*1020150eSMehdi Amini
157*1020150eSMehdi Amini    @classmethod
158*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
159*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
160*1020150eSMehdi Amini        if not frame.IsValid():
161*1020150eSMehdi Amini            result.SetError(
162*1020150eSMehdi Amini                "Can't backtrace without a valid frame (program not running?)"
163*1020150eSMehdi Amini            )
164*1020150eSMehdi Amini        result = frame.EvaluateExpression(
165*1020150eSMehdi Amini            "((bool(*)(bool))mlirDebuggerPrintActionBacktrace)(%d)" % (options.context),
166*1020150eSMehdi Amini            exprOptions,
167*1020150eSMehdi Amini        )
168*1020150eSMehdi Amini        if not result.error.Success():
169*1020150eSMehdi Amini            print("Error printing breakpoints: %s" % (result.error))
170*1020150eSMehdi Amini            return
171*1020150eSMehdi Amini
172*1020150eSMehdi Amini
173*1020150eSMehdi Amini###############################################################################
174*1020150eSMehdi Amini# Cursor manipulation
175*1020150eSMehdi Amini###############################################################################
176*1020150eSMehdi Amini
177*1020150eSMehdi Amini
178*1020150eSMehdi Aminiclass PrintCursor:
179*1020150eSMehdi Amini    @classmethod
180*1020150eSMehdi Amini    def register_mlir_subparser(cls):
181*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
182*1020150eSMehdi Amini            "cursor-print", aliases=["cursor-p"], help="Print the current cursor"
183*1020150eSMehdi Amini        )
184*1020150eSMehdi Amini        cls.parser.add_argument(
185*1020150eSMehdi Amini            "--print-region", "--regions", "-r", default=False, action="store_true"
186*1020150eSMehdi Amini        )
187*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
188*1020150eSMehdi Amini
189*1020150eSMehdi Amini    @classmethod
190*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
191*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
192*1020150eSMehdi Amini        if not frame.IsValid():
193*1020150eSMehdi Amini            result.SetError(
194*1020150eSMehdi Amini                "Can't print cursor without a valid frame (program not running?)"
195*1020150eSMehdi Amini            )
196*1020150eSMehdi Amini        result = frame.EvaluateExpression(
197*1020150eSMehdi Amini            "((bool(*)(bool))mlirDebuggerCursorPrint)(%d)" % (options.print_region),
198*1020150eSMehdi Amini            exprOptions,
199*1020150eSMehdi Amini        )
200*1020150eSMehdi Amini        if not result.error.Success():
201*1020150eSMehdi Amini            print("Error printing cursor: %s" % (result.error))
202*1020150eSMehdi Amini            return
203*1020150eSMehdi Amini
204*1020150eSMehdi Amini
205*1020150eSMehdi Aminiclass SelectCursorFromContext:
206*1020150eSMehdi Amini    @classmethod
207*1020150eSMehdi Amini    def register_mlir_subparser(cls):
208*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
209*1020150eSMehdi Amini            "cursor-select-from-context",
210*1020150eSMehdi Amini            aliases=["cursor-s"],
211*1020150eSMehdi Amini            help="Select the cursor from the current context",
212*1020150eSMehdi Amini        )
213*1020150eSMehdi Amini        cls.parser.add_argument("index", type=int, help="Index in the context")
214*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
215*1020150eSMehdi Amini
216*1020150eSMehdi Amini    @classmethod
217*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
218*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
219*1020150eSMehdi Amini        if not frame.IsValid():
220*1020150eSMehdi Amini            result.SetError(
221*1020150eSMehdi Amini                "Can't manipulate cursor without a valid frame (program not running?)"
222*1020150eSMehdi Amini            )
223*1020150eSMehdi Amini        result = frame.EvaluateExpression(
224*1020150eSMehdi Amini            "((bool(*)(int))mlirDebuggerCursorSelectIRUnitFromContext)(%d)"
225*1020150eSMehdi Amini            % options.index,
226*1020150eSMehdi Amini            exprOptions,
227*1020150eSMehdi Amini        )
228*1020150eSMehdi Amini        if not result.error.Success():
229*1020150eSMehdi Amini            print("Error manipulating cursor: %s" % (result.error))
230*1020150eSMehdi Amini            return
231*1020150eSMehdi Amini
232*1020150eSMehdi Amini
233*1020150eSMehdi Aminiclass CursorSelectParent:
234*1020150eSMehdi Amini    @classmethod
235*1020150eSMehdi Amini    def register_mlir_subparser(cls):
236*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
237*1020150eSMehdi Amini            "cursor-parent", aliases=["cursor-up"], help="Select the cursor parent"
238*1020150eSMehdi Amini        )
239*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
240*1020150eSMehdi Amini
241*1020150eSMehdi Amini    @classmethod
242*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
243*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
244*1020150eSMehdi Amini        if not frame.IsValid():
245*1020150eSMehdi Amini            result.SetError(
246*1020150eSMehdi Amini                "Can't manipulate cursor without a valid frame (program not running?)"
247*1020150eSMehdi Amini            )
248*1020150eSMehdi Amini        result = frame.EvaluateExpression(
249*1020150eSMehdi Amini            "((bool(*)())mlirDebuggerCursorSelectParentIRUnit)()",
250*1020150eSMehdi Amini            exprOptions,
251*1020150eSMehdi Amini        )
252*1020150eSMehdi Amini        if not result.error.Success():
253*1020150eSMehdi Amini            print("Error manipulating cursor: %s" % (result.error))
254*1020150eSMehdi Amini            return
255*1020150eSMehdi Amini
256*1020150eSMehdi Amini
257*1020150eSMehdi Aminiclass SelectCursorChild:
258*1020150eSMehdi Amini    @classmethod
259*1020150eSMehdi Amini    def register_mlir_subparser(cls):
260*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
261*1020150eSMehdi Amini            "cursor-child", aliases=["cursor-c"], help="Select the nth child"
262*1020150eSMehdi Amini        )
263*1020150eSMehdi Amini        cls.parser.add_argument("index", type=int, help="Index of the child to select")
264*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
265*1020150eSMehdi Amini
266*1020150eSMehdi Amini    @classmethod
267*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
268*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
269*1020150eSMehdi Amini        if not frame.IsValid():
270*1020150eSMehdi Amini            result.SetError(
271*1020150eSMehdi Amini                "Can't manipulate cursor without a valid frame (program not running?)"
272*1020150eSMehdi Amini            )
273*1020150eSMehdi Amini        result = frame.EvaluateExpression(
274*1020150eSMehdi Amini            "((bool(*)(int))mlirDebuggerCursorSelectChildIRUnit)(%d)" % options.index,
275*1020150eSMehdi Amini            exprOptions,
276*1020150eSMehdi Amini        )
277*1020150eSMehdi Amini        if not result.error.Success():
278*1020150eSMehdi Amini            print("Error manipulating cursor: %s" % (result.error))
279*1020150eSMehdi Amini            return
280*1020150eSMehdi Amini
281*1020150eSMehdi Amini
282*1020150eSMehdi Aminiclass CursorSelecPrevious:
283*1020150eSMehdi Amini    @classmethod
284*1020150eSMehdi Amini    def register_mlir_subparser(cls):
285*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
286*1020150eSMehdi Amini            "cursor-previous",
287*1020150eSMehdi Amini            aliases=["cursor-prev"],
288*1020150eSMehdi Amini            help="Select the cursor previous element",
289*1020150eSMehdi Amini        )
290*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
291*1020150eSMehdi Amini
292*1020150eSMehdi Amini    @classmethod
293*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
294*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
295*1020150eSMehdi Amini        if not frame.IsValid():
296*1020150eSMehdi Amini            result.SetError(
297*1020150eSMehdi Amini                "Can't manipulate cursor without a valid frame (program not running?)"
298*1020150eSMehdi Amini            )
299*1020150eSMehdi Amini        result = frame.EvaluateExpression(
300*1020150eSMehdi Amini            "((bool(*)())mlirDebuggerCursorSelectPreviousIRUnit)()",
301*1020150eSMehdi Amini            exprOptions,
302*1020150eSMehdi Amini        )
303*1020150eSMehdi Amini        if not result.error.Success():
304*1020150eSMehdi Amini            print("Error manipulating cursor: %s" % (result.error))
305*1020150eSMehdi Amini            return
306*1020150eSMehdi Amini
307*1020150eSMehdi Amini
308*1020150eSMehdi Aminiclass CursorSelecNext:
309*1020150eSMehdi Amini    @classmethod
310*1020150eSMehdi Amini    def register_mlir_subparser(cls):
311*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
312*1020150eSMehdi Amini            "cursor-next", aliases=["cursor-n"], help="Select the cursor next element"
313*1020150eSMehdi Amini        )
314*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
315*1020150eSMehdi Amini
316*1020150eSMehdi Amini    @classmethod
317*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
318*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
319*1020150eSMehdi Amini        if not frame.IsValid():
320*1020150eSMehdi Amini            result.SetError(
321*1020150eSMehdi Amini                "Can't manipulate cursor without a valid frame (program not running?)"
322*1020150eSMehdi Amini            )
323*1020150eSMehdi Amini        result = frame.EvaluateExpression(
324*1020150eSMehdi Amini            "((bool(*)())mlirDebuggerCursorSelectNextIRUnit)()",
325*1020150eSMehdi Amini            exprOptions,
326*1020150eSMehdi Amini        )
327*1020150eSMehdi Amini        if not result.error.Success():
328*1020150eSMehdi Amini            print("Error manipulating cursor: %s" % (result.error))
329*1020150eSMehdi Amini            return
330*1020150eSMehdi Amini
331*1020150eSMehdi Amini
332*1020150eSMehdi Amini###############################################################################
333*1020150eSMehdi Amini# Breakpoints
334*1020150eSMehdi Amini###############################################################################
335*1020150eSMehdi Amini
336*1020150eSMehdi Amini
337*1020150eSMehdi Aminiclass EnableBreakpoint:
338*1020150eSMehdi Amini    @classmethod
339*1020150eSMehdi Amini    def register_mlir_subparser(cls):
340*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
341*1020150eSMehdi Amini            "enable", help="Enable a single breakpoint (given its ID)"
342*1020150eSMehdi Amini        )
343*1020150eSMehdi Amini        cls.parser.add_argument("id", help="ID of the breakpoint to enable")
344*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
345*1020150eSMehdi Amini
346*1020150eSMehdi Amini    @classmethod
347*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
348*1020150eSMehdi Amini        bp = breakpoints.get(int(options.id), None)
349*1020150eSMehdi Amini        if not bp:
350*1020150eSMehdi Amini            result.SetError("No breakpoint with ID %d" % int(options.id))
351*1020150eSMehdi Amini            return
352*1020150eSMehdi Amini        bp.enable(exe_ctx.GetFrame())
353*1020150eSMehdi Amini
354*1020150eSMehdi Amini
355*1020150eSMehdi Aminiclass DisableBreakpoint:
356*1020150eSMehdi Amini    @classmethod
357*1020150eSMehdi Amini    def register_mlir_subparser(cls):
358*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
359*1020150eSMehdi Amini            "disable", help="Disable a single breakpoint (given its ID)"
360*1020150eSMehdi Amini        )
361*1020150eSMehdi Amini        cls.parser.add_argument("id", help="ID of the breakpoint to disable")
362*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
363*1020150eSMehdi Amini
364*1020150eSMehdi Amini    @classmethod
365*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
366*1020150eSMehdi Amini        bp = breakpoints.get(int(options.id), None)
367*1020150eSMehdi Amini        if not bp:
368*1020150eSMehdi Amini            result.SetError("No breakpoint with ID %s" % options.id)
369*1020150eSMehdi Amini            return
370*1020150eSMehdi Amini        bp.disable(exe_ctx.GetFrame())
371*1020150eSMehdi Amini
372*1020150eSMehdi Amini
373*1020150eSMehdi Aminiclass ListBreakpoints:
374*1020150eSMehdi Amini    @classmethod
375*1020150eSMehdi Amini    def register_mlir_subparser(cls):
376*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
377*1020150eSMehdi Amini            "list", help="List all current breakpoints"
378*1020150eSMehdi Amini        )
379*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
380*1020150eSMehdi Amini
381*1020150eSMehdi Amini    @classmethod
382*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
383*1020150eSMehdi Amini        for id, bp in sorted(breakpoints.items()):
384*1020150eSMehdi Amini            print(id, type(id), str(bp), "enabled" if bp.isEnabled else "disabled")
385*1020150eSMehdi Amini
386*1020150eSMehdi Amini
387*1020150eSMehdi Aminiclass Breakpoint:
388*1020150eSMehdi Amini    def __init__(self):
389*1020150eSMehdi Amini        global nextid
390*1020150eSMehdi Amini        self.id = nextid
391*1020150eSMehdi Amini        nextid += 1
392*1020150eSMehdi Amini        breakpoints[self.id] = self
393*1020150eSMehdi Amini        self.isEnabled = True
394*1020150eSMehdi Amini
395*1020150eSMehdi Amini    def enable(self, frame=None):
396*1020150eSMehdi Amini        self.isEnabled = True
397*1020150eSMehdi Amini        if not frame or not frame.IsValid():
398*1020150eSMehdi Amini            return
399*1020150eSMehdi Amini        # use a C cast to force the type of the breakpoint handle to be void * so
400*1020150eSMehdi Amini        # that we don't rely on DWARF. Also add a fake bool return value otherwise
401*1020150eSMehdi Amini        # LLDB can't signal any error with the expression evaluation (at least I don't know how).
402*1020150eSMehdi Amini        cmd = (
403*1020150eSMehdi Amini            "((bool (*)(void *))mlirDebuggerEnableBreakpoint)((void *)%s)" % self.handle
404*1020150eSMehdi Amini        )
405*1020150eSMehdi Amini        result = frame.EvaluateExpression(cmd, exprOptions)
406*1020150eSMehdi Amini        if not result.error.Success():
407*1020150eSMehdi Amini            print("Error enabling breakpoint: %s" % (result.error))
408*1020150eSMehdi Amini            return
409*1020150eSMehdi Amini
410*1020150eSMehdi Amini    def disable(self, frame=None):
411*1020150eSMehdi Amini        self.isEnabled = False
412*1020150eSMehdi Amini        if not frame or not frame.IsValid():
413*1020150eSMehdi Amini            return
414*1020150eSMehdi Amini        # use a C cast to force the type of the breakpoint handle to be void * so
415*1020150eSMehdi Amini        # that we don't rely on DWARF. Also add a fake bool return value otherwise
416*1020150eSMehdi Amini        # LLDB can't signal any error with the expression evaluation (at least I don't know how).
417*1020150eSMehdi Amini        cmd = (
418*1020150eSMehdi Amini            "((bool (*)(void *)) mlirDebuggerDisableBreakpoint)((void *)%s)"
419*1020150eSMehdi Amini            % self.handle
420*1020150eSMehdi Amini        )
421*1020150eSMehdi Amini        result = frame.EvaluateExpression(cmd, exprOptions)
422*1020150eSMehdi Amini        if not result.error.Success():
423*1020150eSMehdi Amini            print("Error disabling breakpoint: %s" % (result.error))
424*1020150eSMehdi Amini            return
425*1020150eSMehdi Amini
426*1020150eSMehdi Amini
427*1020150eSMehdi Aminiclass TagBreakpoint(Breakpoint):
428*1020150eSMehdi Amini    mlir_subcommand = "break-on-tag"
429*1020150eSMehdi Amini
430*1020150eSMehdi Amini    def __init__(self, tag):
431*1020150eSMehdi Amini        super().__init__()
432*1020150eSMehdi Amini        self.tag = tag
433*1020150eSMehdi Amini
434*1020150eSMehdi Amini    def __str__(self):
435*1020150eSMehdi Amini        return "[%d] TagBreakpoint(%s)" % (self.id, self.tag)
436*1020150eSMehdi Amini
437*1020150eSMehdi Amini    @classmethod
438*1020150eSMehdi Amini    def register_mlir_subparser(cls):
439*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
440*1020150eSMehdi Amini            cls.mlir_subcommand, help="add a breakpoint on actions' tag matching"
441*1020150eSMehdi Amini        )
442*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
443*1020150eSMehdi Amini        cls.parser.add_argument("tag", help="tag to match")
444*1020150eSMehdi Amini
445*1020150eSMehdi Amini    @classmethod
446*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
447*1020150eSMehdi Amini        breakpoint = TagBreakpoint(options.tag)
448*1020150eSMehdi Amini        print("Added breakpoint %s" % str(breakpoint))
449*1020150eSMehdi Amini
450*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
451*1020150eSMehdi Amini        if frame.IsValid():
452*1020150eSMehdi Amini            breakpoint.install(frame)
453*1020150eSMehdi Amini
454*1020150eSMehdi Amini    def install(self, frame):
455*1020150eSMehdi Amini        result = frame.EvaluateExpression(
456*1020150eSMehdi Amini            '((void *(*)(const char *))mlirDebuggerAddTagBreakpoint)("%s")'
457*1020150eSMehdi Amini            % (self.tag),
458*1020150eSMehdi Amini            exprOptions,
459*1020150eSMehdi Amini        )
460*1020150eSMehdi Amini        if not result.error.Success():
461*1020150eSMehdi Amini            print("Error installing breakpoint: %s" % (result.error))
462*1020150eSMehdi Amini            return
463*1020150eSMehdi Amini        # Save the handle, this is necessary to implement enable/disable.
464*1020150eSMehdi Amini        self.handle = result.GetValue()
465*1020150eSMehdi Amini
466*1020150eSMehdi Amini
467*1020150eSMehdi Aminiclass FileLineBreakpoint(Breakpoint):
468*1020150eSMehdi Amini    mlir_subcommand = "break-on-file"
469*1020150eSMehdi Amini
470*1020150eSMehdi Amini    def __init__(self, file, line, col):
471*1020150eSMehdi Amini        super().__init__()
472*1020150eSMehdi Amini        self.file = file
473*1020150eSMehdi Amini        self.line = line
474*1020150eSMehdi Amini        self.col = col
475*1020150eSMehdi Amini
476*1020150eSMehdi Amini    def __str__(self):
477*1020150eSMehdi Amini        return "[%d] FileLineBreakpoint(%s, %d, %d)" % (
478*1020150eSMehdi Amini            self.id,
479*1020150eSMehdi Amini            self.file,
480*1020150eSMehdi Amini            self.line,
481*1020150eSMehdi Amini            self.col,
482*1020150eSMehdi Amini        )
483*1020150eSMehdi Amini
484*1020150eSMehdi Amini    @classmethod
485*1020150eSMehdi Amini    def register_mlir_subparser(cls):
486*1020150eSMehdi Amini        cls.parser = MlirDebug.subparsers.add_parser(
487*1020150eSMehdi Amini            cls.mlir_subcommand,
488*1020150eSMehdi Amini            help="add a breakpoint that filters on location of the IR affected by an action. The syntax is file:line:col where file and col are optional",
489*1020150eSMehdi Amini        )
490*1020150eSMehdi Amini        cls.parser.set_defaults(func=cls.process_options)
491*1020150eSMehdi Amini        cls.parser.add_argument("location", type=str)
492*1020150eSMehdi Amini
493*1020150eSMehdi Amini    @classmethod
494*1020150eSMehdi Amini    def process_options(cls, options, debugger, command, exe_ctx, result):
495*1020150eSMehdi Amini        split_loc = options.location.split(":")
496*1020150eSMehdi Amini        file = split_loc[0]
497*1020150eSMehdi Amini        line = int(split_loc[1]) if len(split_loc) > 1 else -1
498*1020150eSMehdi Amini        col = int(split_loc[2]) if len(split_loc) > 2 else -1
499*1020150eSMehdi Amini        breakpoint = FileLineBreakpoint(file, line, col)
500*1020150eSMehdi Amini        print("Added breakpoint %s" % str(breakpoint))
501*1020150eSMehdi Amini
502*1020150eSMehdi Amini        frame = exe_ctx.GetFrame()
503*1020150eSMehdi Amini        if frame.IsValid():
504*1020150eSMehdi Amini            breakpoint.install(frame)
505*1020150eSMehdi Amini
506*1020150eSMehdi Amini    def install(self, frame):
507*1020150eSMehdi Amini        result = frame.EvaluateExpression(
508*1020150eSMehdi Amini            '((void *(*)(const char *, int, int))mlirDebuggerAddFileLineColLocBreakpoint)("%s", %d, %d)'
509*1020150eSMehdi Amini            % (self.file, self.line, self.col),
510*1020150eSMehdi Amini            exprOptions,
511*1020150eSMehdi Amini        )
512*1020150eSMehdi Amini        if not result.error.Success():
513*1020150eSMehdi Amini            print("Error installing breakpoint: %s" % (result.error))
514*1020150eSMehdi Amini            return
515*1020150eSMehdi Amini        # Save the handle, this is necessary to implement enable/disable.
516*1020150eSMehdi Amini        self.handle = result.GetValue()
517*1020150eSMehdi Amini
518*1020150eSMehdi Amini
519*1020150eSMehdi Aminidef on_start(frame, bpno, err):
520*1020150eSMehdi Amini    print("MLIR debugger attaching...")
521*1020150eSMehdi Amini    for _, bp in sorted(breakpoints.items()):
522*1020150eSMehdi Amini        if bp.isEnabled:
523*1020150eSMehdi Amini            print("Installing breakpoint %s" % (str(bp)))
524*1020150eSMehdi Amini            bp.install(frame)
525*1020150eSMehdi Amini        else:
526*1020150eSMehdi Amini            print("Skipping disabled breakpoint %s" % (str(bp)))
527*1020150eSMehdi Amini
528*1020150eSMehdi Amini    return True
529*1020150eSMehdi Amini
530*1020150eSMehdi Amini
531*1020150eSMehdi Aminidef __lldb_init_module(debugger, dict):
532*1020150eSMehdi Amini    target = debugger.GetTargetAtIndex(0)
533*1020150eSMehdi Amini    debugger.SetAsync(False)
534*1020150eSMehdi Amini    if not target:
535*1020150eSMehdi Amini        print("No target is loaded, please load a target before loading this script.")
536*1020150eSMehdi Amini        return
537*1020150eSMehdi Amini    if debugger.GetNumTargets() > 1:
538*1020150eSMehdi Amini        print(
539*1020150eSMehdi Amini            "Multiple targets (%s) loaded, attaching MLIR debugging to %s"
540*1020150eSMehdi Amini            % (debugger.GetNumTargets(), target)
541*1020150eSMehdi Amini        )
542*1020150eSMehdi Amini
543*1020150eSMehdi Amini    # Register all classes that have a register_lldb_command method
544*1020150eSMehdi Amini    module_name = __name__
545*1020150eSMehdi Amini    parser = MlirDebug.create_options()
546*1020150eSMehdi Amini    MlirDebug.__doc__ = parser.format_help()
547*1020150eSMehdi Amini
548*1020150eSMehdi Amini    # Add the MLIR entry point to LLDB as a command.
549*1020150eSMehdi Amini    command = "command script add -o -c %s.%s %s" % (
550*1020150eSMehdi Amini        module_name,
551*1020150eSMehdi Amini        MlirDebug.__name__,
552*1020150eSMehdi Amini        MlirDebug.lldb_command,
553*1020150eSMehdi Amini    )
554*1020150eSMehdi Amini    debugger.HandleCommand(command)
555*1020150eSMehdi Amini
556*1020150eSMehdi Amini    main_bp = target.BreakpointCreateByName("main")
557*1020150eSMehdi Amini    main_bp.SetScriptCallbackFunction("action_debugging.on_start")
558*1020150eSMehdi Amini    main_bp.SetAutoContinue(auto_continue=True)
559*1020150eSMehdi Amini
560*1020150eSMehdi Amini    on_breackpoint = target.BreakpointCreateByName("mlirDebuggerBreakpointHook")
561*1020150eSMehdi Amini
562*1020150eSMehdi Amini    print(
563*1020150eSMehdi Amini        'The "{0}" command has been installed for target `{1}`, type "help {0}" or "{0} '
564*1020150eSMehdi Amini        '--help" for detailed help.'.format(MlirDebug.lldb_command, target)
565*1020150eSMehdi Amini    )
566*1020150eSMehdi Amini    for _name, cls in inspect.getmembers(sys.modules[module_name]):
567*1020150eSMehdi Amini        if inspect.isclass(cls) and getattr(cls, "register_mlir_subparser", None):
568*1020150eSMehdi Amini            cls.register_mlir_subparser()
569