Index: utils/debug-diag.py =================================================================== --- /dev/null +++ utils/debug-diag.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# This tool allows you to find a backtrace for a reported diagnostic in Clang. +# +# To use: +# 1) Ensure that diagtool is compiled and is up-to-date +# 2) Invoke the tool: +# debug-diag warn_some_warning /path/to/clang -- -cc1 myfile.cpp + +import os +import subprocess +import sys +import tempfile + +def invokeLLDB(diagCode, clang, args): + # Set a breakpoint at the diagnostic + command = """breakpoint set -n DiagnosticsEngine::Report +breakpoint modify -c "DiagID == %d" +run +bt""" % (diagCode) + + filename = "" + with tempfile.NamedTemporaryFile(delete=False) as f: + f.write(command) + filename = f.name + f.close() + + p = None + try: + p = subprocess.Popen(["lldb","-s",f.name, clang,"--"] + args) + p.wait() + except KeyboardInterrupt: + print >>sys.stderr, 'Killing LLDB.' + p.terminate() + os.unlink(filename) + except: + os.unlink(filename) + raise + +def main(): + import argparse + + description = "Runs clang in a debugger and stops at a breakpoint when the given diagnostic is reported" + parser = argparse.ArgumentParser(description=description) + parser.add_argument("diag", metavar="diagnostic", nargs=1, + help="name of the diagnostic") + parser.add_argument("clang", metavar="clang", nargs=1, + help="path to clang") + parser.add_argument("arguments", metavar="arg", nargs="+", + help="command line arguments that should be passed to clang") + args = parser.parse_args() + + if args.arguments[0] != "-cc1": + # Clang must run in -cc1 to avoid the fork which breaks debugging. + # FIXME: Invoke the driver and figure out the -cc1 options. + print >>sys.stderr, "The '-cc1' option should be passed to clang" + sys.exit(1) + + # Compute the diagnostic code for the given diagnostic. + # FIXME: Diagtool binary might have out-of-date ids, when clang's + # diagnostics are modified and clang is rebuilt but diagtool wasn't. The + # script should try to identify this issue. + diagtool = os.path.join(os.path.dirname(args.clang[0]), "diagtool") + p = subprocess.Popen([diagtool,'find-diagnostic-id',args.diag[0]], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + out,_ = p.communicate() + diagCode = None + try: + diagCode = int(out) + except ValueError: + # diag-tool will report to stderr. + sys.exit(1) + + # Use LLDB to run clang and stop at the diagnostic. + invokeLLDB(diagCode, args.clang[0], args.arguments) + +if __name__ == '__main__': + main()