1#!/usr/bin/env python 2""" 3A gdb-compatible frontend for lldb that implements just enough 4commands to run the tests in the debuginfo-tests repository with lldb. 5""" 6 7# ---------------------------------------------------------------------- 8# Auto-detect lldb python module. 9import commands, platform, os, sys 10try: 11 # Just try for LLDB in case PYTHONPATH is already correctly setup. 12 import lldb 13except ImportError: 14 lldb_python_dirs = list() 15 # lldb is not in the PYTHONPATH, try some defaults for the current platform. 16 platform_system = platform.system() 17 if platform_system == 'Darwin': 18 # On Darwin, try the currently selected Xcode directory 19 xcode_dir = commands.getoutput("xcode-select --print-path") 20 if xcode_dir: 21 lldb_python_dirs.append(os.path.realpath(xcode_dir + 22'/../SharedFrameworks/LLDB.framework/Resources/Python')) 23 lldb_python_dirs.append(xcode_dir + 24'/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 25 lldb_python_dirs.append( 26'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 27 success = False 28 for lldb_python_dir in lldb_python_dirs: 29 if os.path.exists(lldb_python_dir): 30 if not (sys.path.__contains__(lldb_python_dir)): 31 sys.path.append(lldb_python_dir) 32 try: 33 import lldb 34 except ImportError: 35 pass 36 else: 37 print 'imported lldb from: "%s"' % (lldb_python_dir) 38 success = True 39 break 40 if not success: 41 print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" 42 sys.exit(1) 43# ---------------------------------------------------------------------- 44 45# Command line option handling. 46import argparse 47parser = argparse.ArgumentParser(description=__doc__) 48parser.add_argument('--quiet', '-q', action="store_true", help='ignored') 49parser.add_argument('-batch', action="store_true", 50 help='exit after processing comand line') 51parser.add_argument('-n', action="store_true", help='ignore .lldb file') 52parser.add_argument('-x', dest='script', type=file, help='execute commands from file') 53parser.add_argument("target", help="the program to debug") 54args = parser.parse_args() 55 56 57# Create a new debugger instance. 58debugger = lldb.SBDebugger.Create() 59debugger.SkipLLDBInitFiles(args.n) 60 61# Make sure to clean up the debugger on exit. 62import atexit 63def on_exit(): 64 debugger.Terminate() 65atexit.register(on_exit) 66 67# Don't return from lldb function calls until the process stops. 68debugger.SetAsync(False) 69 70# Create a target from a file and arch. 71arch = os.popen("file "+args.target).read().split()[-1] 72target = debugger.CreateTargetWithFileAndArch(args.target, arch) 73 74if not target: 75 print "Could not create target", args.target 76 sys.exit(1) 77 78if not args.script: 79 print "Interactive mode is not implemented." 80 sys.exit(1) 81 82import re 83for command in args.script: 84 # Strip newline and whitespaces and split into words. 85 cmd = command[:-1].strip().split() 86 if not cmd: 87 continue 88 89 print '> %s'% command[:-1] 90 91 try: 92 if re.match('^r|(run)$', cmd[0]): 93 error = lldb.SBError() 94 launchinfo = lldb.SBLaunchInfo([]) 95 launchinfo.SetWorkingDirectory(os.getcwd()) 96 process = target.Launch(launchinfo, error) 97 print error 98 if not process or error.fail: 99 state = process.GetState() 100 print "State = %d" % state 101 print """ 102ERROR: Could not launch process. 103NOTE: There are several reasons why this may happen: 104 * Root needs to run "DevToolsSecurity --enable". 105 * Older versions of lldb cannot launch more than one process simultaneously. 106""" 107 sys.exit(1) 108 109 elif re.match('^b|(break)$', cmd[0]) and len(cmd) == 2: 110 if re.match('[0-9]+', cmd[1]): 111 # b line 112 mainfile = target.FindFunctions('main')[0].compile_unit.file 113 print target.BreakpointCreateByLocation(mainfile, int(cmd[1])) 114 else: 115 # b file:line 116 file, line = cmd[1].split(':') 117 print target.BreakpointCreateByLocation(file, int(line)) 118 119 elif re.match('^ptype$', cmd[0]) and len(cmd) == 2: 120 # GDB's ptype has multiple incarnations depending on its 121 # argument (global variable, function, type). The definition 122 # here is for looking up the signature of a function and only 123 # if that fails it looks for a type with that name. 124 # Type lookup in LLDB would be "image lookup --type". 125 for elem in target.FindFunctions(cmd[1]): 126 print elem.function.type 127 continue 128 print target.FindFirstType(cmd[1]) 129 130 elif re.match('^po$', cmd[0]) and len(cmd) > 1: 131 try: 132 opts = lldb.SBExpressionOptions() 133 opts.SetFetchDynamicValue(True) 134 opts.SetCoerceResultToId(True) 135 print target.EvaluateExpression(' '.join(cmd[1:]), opts) 136 except: 137 # FIXME: This is a fallback path for the lab.llvm.org 138 # buildbot running OS X 10.7; it should be removed. 139 thread = process.GetThreadAtIndex(0) 140 frame = thread.GetFrameAtIndex(0) 141 print frame.EvaluateExpression(' '.join(cmd[1:])) 142 143 elif re.match('^p|(print)$', cmd[0]) and len(cmd) > 1: 144 thread = process.GetThreadAtIndex(0) 145 frame = thread.GetFrameAtIndex(0) 146 print frame.EvaluateExpression(' '.join(cmd[1:])) 147 148 elif re.match('^n|(next)$', cmd[0]): 149 thread = process.GetThreadAtIndex(0) 150 thread.StepOver() 151 152 elif re.match('^q|(quit)$', cmd[0]): 153 sys.exit(0) 154 155 else: 156 print debugger.HandleCommand(' '.join(cmd)) 157 158 except SystemExit: 159 raise 160 except: 161 print 'Could not handle the command "%s"' % ' '.join(cmd) 162 163