Index: utils/clangdiag.py =================================================================== --- /dev/null +++ utils/clangdiag.py @@ -0,0 +1,124 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# +# # To use this in the embedded python interpreter using "lldb" just +# import it with the full path using the "command script import" +# command +# (lldb) command script import /path/to/clandiag.py +#---------------------------------------------------------------------- + +import lldb +import argparse +import commands +import shlex +import os +from subprocess import check_output as qx; + +# State +Breakpoints = [] +target = None +diagtool = None + +class MyParser(argparse.ArgumentParser): + def format_help(self): + return ''' Commands for operating on clang diagnostic breakpoints + +Syntax: clangdiag + +The following subcommands are supported: + + enable -- Enable clang diagnostic breakpoints. + disable -- Disable all clang diagnostic breakpoints. +''' + +def create_diag_options(): + parser = MyParser(prog='clangdiag') + subparsers = parser.add_subparsers( + title='subcommands', + dest='subcommands', + metavar='') + disable_parser = subparsers.add_parser('disable') + enable_parser = subparsers.add_parser('enable') + return parser + +def setDiagBreakpoint(frame, bp_loc, dict): + id = frame.FindVariable("DiagID").GetValue() + if id is None: + print('id is None') + return False + + global target + global diagtool + global Breakpoints + + name = qx([diagtool, "find-diagnostic-id", id]).rstrip(); + bp = target.BreakpointCreateBySourceRegex(name, lldb.SBFileSpec()) + Breakpoints.append(bp) + + return False + +def enable(debugger, args): + # Always disable existing breakpoints + disable(debugger) + + global target + global diagtool + global Breakpoints + + target = debugger.GetSelectedTarget() + exe = target.GetExecutable() + if not exe.Exists(): + print('Target (%s) not set.' % exe.GetFilename()) + return + diagtool = os.path.join(exe.GetDirectory(), 'diagtool') + if not os.path.exists(diagtool): + print('diagtool not found along side %s' % exe) + return + + bp = target.BreakpointCreateByName('DiagnosticsEngine::Report') + bp.SetScriptCallbackFunction('clangdiag.setDiagBreakpoint') + Breakpoints.append(bp) + + return + +def disable(debugger): + global target + global diagtool + global Breakpoints + # Remove all diag breakpoints. + for bp in Breakpoints: + target.BreakpointDelete(bp.GetID()) + target = None + diagtool = None + Breakpoints = [] + return + +def the_diag_command(debugger, command, result, dict): + # Use the Shell Lexer to properly parse up command options just like a + # shell would + command_args = shlex.split(command) + parser = create_diag_options() + try: + args = parser.parse_args(command_args) + except: + return + + if args.subcommands == 'enable': + enable(debugger, args) + else: + disable(debugger) + + return + +def __lldb_init_module(debugger, dict): + # This initializer is being run from LLDB in the embedded command interpreter + # Make the options so we can generate the help text for the new LLDB + # command line command prior to registering it with LLDB below + parser = create_diag_options() + the_diag_command.__doc__ = parser.format_help() + # Add any commands contained in this module to LLDB + debugger.HandleCommand( + 'command script add -f clangdiag.the_diag_command clangdiag') + print 'The "clangdiag" command has been installed, type "help clangdiag" or "clangdiag --help" for detailed help.'