3 # ---------------------------------------------------------------------
4 # Be sure to add the python path that points to the LLDB shared library.
6 # # To use this in the embedded python interpreter using "lldb" just
7 # import it with the full path using the "command script import"
9 # (lldb) command script import /path/to/cmdtemplate.py
10 # ---------------------------------------------------------------------
18 # Each new breakpoint gets a unique ID starting from 1.
20 # List of breakpoint set from python, the key is the ID and the value the
21 # actual breakpoint. These are NOT LLDB SBBreakpoint objects.
24 exprOptions
= lldb
.SBExpressionOptions()
25 exprOptions
.SetIgnoreBreakpoints()
26 exprOptions
.SetLanguage(lldb
.eLanguageTypeC
)
30 """MLIR debugger commands
31 This is the class that hooks into LLDB and registers the `mlir` command.
32 Other providers can register subcommands below this one.
38 def __init__(self
, debugger
, unused
):
41 self
.help_string
= MlirDebug
.parser
.format_help()
44 def create_options(cls
):
46 return MlirDebug
.parser
47 usage
= "usage: %s [options]" % (cls
.lldb_command
)
50 # Pass add_help_option = False, since this keeps the command in line
51 # with lldb commands, and we wire up "help command" to work by
52 # providing the long & short help methods below.
53 MlirDebug
.parser
= argparse
.ArgumentParser(
54 prog
=cls
.lldb_command
, usage
=usage
, description
=description
, add_help
=False
56 MlirDebug
.subparsers
= MlirDebug
.parser
.add_subparsers(dest
="command")
57 return MlirDebug
.parser
59 def get_short_help(self
):
60 return "MLIR debugger commands"
62 def get_long_help(self
):
63 return self
.help_string
65 def __call__(self
, debugger
, command
, exe_ctx
, result
):
66 # Use the Shell Lexer to properly parse up command options just like a
68 command_args
= shlex
.split(command
)
71 args
= MlirDebug
.parser
.parse_args(command_args
)
73 result
.SetError("option parsing failed")
75 args
.func(args
, debugger
, command
, exe_ctx
, result
)
78 def on_process_start(frame
, bp_loc
, dict):
79 print("Process started")
83 # Define the subcommands that controls what to do when a breakpoint is hit.
84 # The key is the subcommand name, the value is a tuple of the command ID to
85 # pass to MLIR and the help string.
87 "apply": (1, "Apply the current action and continue the execution"),
88 "skip": (2, "Skip the current action and continue the execution"),
89 "step": (3, "Step into the current action"),
90 "next": (4, "Step over the current action"),
91 "finish": (5, "Step out of the current action"),
95 def register_mlir_subparser(cls
):
96 for cmd
, (cmdInt
, help) in cls
.commands
.items():
97 parser
= MlirDebug
.subparsers
.add_parser(
101 parser
.set_defaults(func
=cls
.process_options
)
104 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
105 frame
= exe_ctx
.GetFrame()
106 if not frame
.IsValid():
107 result
.SetError("No valid frame (program not running?)")
109 cmdInt
= cls
.commands
.get(options
.command
, None)
111 result
.SetError("Invalid command: %s" % (options
.command
))
114 result
= frame
.EvaluateExpression(
115 "((bool (*)(int))mlirDebuggerSetControl)(%d)" % (cmdInt
[0]),
118 if not result
.error
.Success():
119 print("Error setting up command: %s" % (result
.error
))
121 debugger
.SetAsync(True)
122 result
= exe_ctx
.GetProcess().Continue()
123 debugger
.SetAsync(False)
128 def register_mlir_subparser(cls
):
129 cls
.parser
= MlirDebug
.subparsers
.add_parser(
130 "context", help="Print the current context"
132 cls
.parser
.set_defaults(func
=cls
.process_options
)
135 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
136 frame
= exe_ctx
.GetFrame()
137 if not frame
.IsValid():
138 result
.SetError("Can't print context without a valid frame")
140 result
= frame
.EvaluateExpression(
141 "((bool (*)())&mlirDebuggerPrintContext)()", exprOptions
143 if not result
.error
.Success():
144 print("Error printing context: %s" % (result
.error
))
150 def register_mlir_subparser(cls
):
151 cls
.parser
= MlirDebug
.subparsers
.add_parser(
152 "backtrace", aliases
=["bt"], help="Print the current backtrace"
154 cls
.parser
.set_defaults(func
=cls
.process_options
)
155 cls
.parser
.add_argument("--context", default
=False, action
="store_true")
158 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
159 frame
= exe_ctx
.GetFrame()
160 if not frame
.IsValid():
162 "Can't backtrace without a valid frame (program not running?)"
164 result
= frame
.EvaluateExpression(
165 "((bool(*)(bool))mlirDebuggerPrintActionBacktrace)(%d)" % (options
.context
),
168 if not result
.error
.Success():
169 print("Error printing breakpoints: %s" % (result
.error
))
173 ###############################################################################
174 # Cursor manipulation
175 ###############################################################################
180 def register_mlir_subparser(cls
):
181 cls
.parser
= MlirDebug
.subparsers
.add_parser(
182 "cursor-print", aliases
=["cursor-p"], help="Print the current cursor"
184 cls
.parser
.add_argument(
185 "--print-region", "--regions", "-r", default
=False, action
="store_true"
187 cls
.parser
.set_defaults(func
=cls
.process_options
)
190 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
191 frame
= exe_ctx
.GetFrame()
192 if not frame
.IsValid():
194 "Can't print cursor without a valid frame (program not running?)"
196 result
= frame
.EvaluateExpression(
197 "((bool(*)(bool))mlirDebuggerCursorPrint)(%d)" % (options
.print_region
),
200 if not result
.error
.Success():
201 print("Error printing cursor: %s" % (result
.error
))
205 class SelectCursorFromContext
:
207 def register_mlir_subparser(cls
):
208 cls
.parser
= MlirDebug
.subparsers
.add_parser(
209 "cursor-select-from-context",
210 aliases
=["cursor-s"],
211 help="Select the cursor from the current context",
213 cls
.parser
.add_argument("index", type=int, help="Index in the context")
214 cls
.parser
.set_defaults(func
=cls
.process_options
)
217 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
218 frame
= exe_ctx
.GetFrame()
219 if not frame
.IsValid():
221 "Can't manipulate cursor without a valid frame (program not running?)"
223 result
= frame
.EvaluateExpression(
224 "((bool(*)(int))mlirDebuggerCursorSelectIRUnitFromContext)(%d)"
228 if not result
.error
.Success():
229 print("Error manipulating cursor: %s" % (result
.error
))
233 class CursorSelectParent
:
235 def register_mlir_subparser(cls
):
236 cls
.parser
= MlirDebug
.subparsers
.add_parser(
237 "cursor-parent", aliases
=["cursor-up"], help="Select the cursor parent"
239 cls
.parser
.set_defaults(func
=cls
.process_options
)
242 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
243 frame
= exe_ctx
.GetFrame()
244 if not frame
.IsValid():
246 "Can't manipulate cursor without a valid frame (program not running?)"
248 result
= frame
.EvaluateExpression(
249 "((bool(*)())mlirDebuggerCursorSelectParentIRUnit)()",
252 if not result
.error
.Success():
253 print("Error manipulating cursor: %s" % (result
.error
))
257 class SelectCursorChild
:
259 def register_mlir_subparser(cls
):
260 cls
.parser
= MlirDebug
.subparsers
.add_parser(
261 "cursor-child", aliases
=["cursor-c"], help="Select the nth child"
263 cls
.parser
.add_argument("index", type=int, help="Index of the child to select")
264 cls
.parser
.set_defaults(func
=cls
.process_options
)
267 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
268 frame
= exe_ctx
.GetFrame()
269 if not frame
.IsValid():
271 "Can't manipulate cursor without a valid frame (program not running?)"
273 result
= frame
.EvaluateExpression(
274 "((bool(*)(int))mlirDebuggerCursorSelectChildIRUnit)(%d)" % options
.index
,
277 if not result
.error
.Success():
278 print("Error manipulating cursor: %s" % (result
.error
))
282 class CursorSelecPrevious
:
284 def register_mlir_subparser(cls
):
285 cls
.parser
= MlirDebug
.subparsers
.add_parser(
287 aliases
=["cursor-prev"],
288 help="Select the cursor previous element",
290 cls
.parser
.set_defaults(func
=cls
.process_options
)
293 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
294 frame
= exe_ctx
.GetFrame()
295 if not frame
.IsValid():
297 "Can't manipulate cursor without a valid frame (program not running?)"
299 result
= frame
.EvaluateExpression(
300 "((bool(*)())mlirDebuggerCursorSelectPreviousIRUnit)()",
303 if not result
.error
.Success():
304 print("Error manipulating cursor: %s" % (result
.error
))
308 class CursorSelecNext
:
310 def register_mlir_subparser(cls
):
311 cls
.parser
= MlirDebug
.subparsers
.add_parser(
312 "cursor-next", aliases
=["cursor-n"], help="Select the cursor next element"
314 cls
.parser
.set_defaults(func
=cls
.process_options
)
317 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
318 frame
= exe_ctx
.GetFrame()
319 if not frame
.IsValid():
321 "Can't manipulate cursor without a valid frame (program not running?)"
323 result
= frame
.EvaluateExpression(
324 "((bool(*)())mlirDebuggerCursorSelectNextIRUnit)()",
327 if not result
.error
.Success():
328 print("Error manipulating cursor: %s" % (result
.error
))
332 ###############################################################################
334 ###############################################################################
337 class EnableBreakpoint
:
339 def register_mlir_subparser(cls
):
340 cls
.parser
= MlirDebug
.subparsers
.add_parser(
341 "enable", help="Enable a single breakpoint (given its ID)"
343 cls
.parser
.add_argument("id", help="ID of the breakpoint to enable")
344 cls
.parser
.set_defaults(func
=cls
.process_options
)
347 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
348 bp
= breakpoints
.get(int(options
.id), None)
350 result
.SetError("No breakpoint with ID %d" % int(options
.id))
352 bp
.enable(exe_ctx
.GetFrame())
355 class DisableBreakpoint
:
357 def register_mlir_subparser(cls
):
358 cls
.parser
= MlirDebug
.subparsers
.add_parser(
359 "disable", help="Disable a single breakpoint (given its ID)"
361 cls
.parser
.add_argument("id", help="ID of the breakpoint to disable")
362 cls
.parser
.set_defaults(func
=cls
.process_options
)
365 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
366 bp
= breakpoints
.get(int(options
.id), None)
368 result
.SetError("No breakpoint with ID %s" % options
.id)
370 bp
.disable(exe_ctx
.GetFrame())
373 class ListBreakpoints
:
375 def register_mlir_subparser(cls
):
376 cls
.parser
= MlirDebug
.subparsers
.add_parser(
377 "list", help="List all current breakpoints"
379 cls
.parser
.set_defaults(func
=cls
.process_options
)
382 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
383 for id, bp
in sorted(breakpoints
.items()):
384 print(id, type(id), str(bp
), "enabled" if bp
.isEnabled
else "disabled")
392 breakpoints
[self
.id] = self
393 self
.isEnabled
= True
395 def enable(self
, frame
=None):
396 self
.isEnabled
= True
397 if not frame
or not frame
.IsValid():
399 # use a C cast to force the type of the breakpoint handle to be void * so
400 # that we don't rely on DWARF. Also add a fake bool return value otherwise
401 # LLDB can't signal any error with the expression evaluation (at least I don't know how).
403 "((bool (*)(void *))mlirDebuggerEnableBreakpoint)((void *)%s)" % self
.handle
405 result
= frame
.EvaluateExpression(cmd
, exprOptions
)
406 if not result
.error
.Success():
407 print("Error enabling breakpoint: %s" % (result
.error
))
410 def disable(self
, frame
=None):
411 self
.isEnabled
= False
412 if not frame
or not frame
.IsValid():
414 # use a C cast to force the type of the breakpoint handle to be void * so
415 # that we don't rely on DWARF. Also add a fake bool return value otherwise
416 # LLDB can't signal any error with the expression evaluation (at least I don't know how).
418 "((bool (*)(void *)) mlirDebuggerDisableBreakpoint)((void *)%s)"
421 result
= frame
.EvaluateExpression(cmd
, exprOptions
)
422 if not result
.error
.Success():
423 print("Error disabling breakpoint: %s" % (result
.error
))
427 class TagBreakpoint(Breakpoint
):
428 mlir_subcommand
= "break-on-tag"
430 def __init__(self
, tag
):
435 return "[%d] TagBreakpoint(%s)" % (self
.id, self
.tag
)
438 def register_mlir_subparser(cls
):
439 cls
.parser
= MlirDebug
.subparsers
.add_parser(
440 cls
.mlir_subcommand
, help="add a breakpoint on actions' tag matching"
442 cls
.parser
.set_defaults(func
=cls
.process_options
)
443 cls
.parser
.add_argument("tag", help="tag to match")
446 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
447 breakpoint
= TagBreakpoint(options
.tag
)
448 print("Added breakpoint %s" % str(breakpoint
))
450 frame
= exe_ctx
.GetFrame()
452 breakpoint
.install(frame
)
454 def install(self
, frame
):
455 result
= frame
.EvaluateExpression(
456 '((void *(*)(const char *))mlirDebuggerAddTagBreakpoint)("%s")'
460 if not result
.error
.Success():
461 print("Error installing breakpoint: %s" % (result
.error
))
463 # Save the handle, this is necessary to implement enable/disable.
464 self
.handle
= result
.GetValue()
467 class FileLineBreakpoint(Breakpoint
):
468 mlir_subcommand
= "break-on-file"
470 def __init__(self
, file, line
, col
):
477 return "[%d] FileLineBreakpoint(%s, %d, %d)" % (
485 def register_mlir_subparser(cls
):
486 cls
.parser
= MlirDebug
.subparsers
.add_parser(
488 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",
490 cls
.parser
.set_defaults(func
=cls
.process_options
)
491 cls
.parser
.add_argument("location", type=str)
494 def process_options(cls
, options
, debugger
, command
, exe_ctx
, result
):
495 split_loc
= options
.location
.split(":")
497 line
= int(split_loc
[1]) if len(split_loc
) > 1 else -1
498 col
= int(split_loc
[2]) if len(split_loc
) > 2 else -1
499 breakpoint
= FileLineBreakpoint(file, line
, col
)
500 print("Added breakpoint %s" % str(breakpoint
))
502 frame
= exe_ctx
.GetFrame()
504 breakpoint
.install(frame
)
506 def install(self
, frame
):
507 result
= frame
.EvaluateExpression(
508 '((void *(*)(const char *, int, int))mlirDebuggerAddFileLineColLocBreakpoint)("%s", %d, %d)'
509 % (self
.file, self
.line
, self
.col
),
512 if not result
.error
.Success():
513 print("Error installing breakpoint: %s" % (result
.error
))
515 # Save the handle, this is necessary to implement enable/disable.
516 self
.handle
= result
.GetValue()
519 def on_start(frame
, bpno
, err
):
520 print("MLIR debugger attaching...")
521 for _
, bp
in sorted(breakpoints
.items()):
523 print("Installing breakpoint %s" % (str(bp
)))
526 print("Skipping disabled breakpoint %s" % (str(bp
)))
531 def __lldb_init_module(debugger
, dict):
532 target
= debugger
.GetTargetAtIndex(0)
533 debugger
.SetAsync(False)
535 print("No target is loaded, please load a target before loading this script.")
537 if debugger
.GetNumTargets() > 1:
539 "Multiple targets (%s) loaded, attaching MLIR debugging to %s"
540 % (debugger
.GetNumTargets(), target
)
543 # Register all classes that have a register_lldb_command method
544 module_name
= __name__
545 parser
= MlirDebug
.create_options()
546 MlirDebug
.__doc
__ = parser
.format_help()
548 # Add the MLIR entry point to LLDB as a command.
549 command
= "command script add -o -c %s.%s %s" % (
552 MlirDebug
.lldb_command
,
554 debugger
.HandleCommand(command
)
556 main_bp
= target
.BreakpointCreateByName("main")
557 main_bp
.SetScriptCallbackFunction("action_debugging.on_start")
558 main_bp
.SetAutoContinue(auto_continue
=True)
560 on_breackpoint
= target
.BreakpointCreateByName("mlirDebuggerBreakpointHook")
563 'The "{0}" command has been installed for target `{1}`, type "help {0}" or "{0} '
564 '--help" for detailed help.'.format(MlirDebug
.lldb_command
, target
)
566 for _name
, cls
in inspect
.getmembers(sys
.modules
[module_name
]):
567 if inspect
.isclass(cls
) and getattr(cls
, "register_mlir_subparser", None):
568 cls
.register_mlir_subparser()