Index: lldb/utils/vim-lldb/README =================================================================== --- lldb/utils/vim-lldb/README +++ /dev/null @@ -1,59 +0,0 @@ - -================= -LLDB Vim Frontend -================= - -Prerequisites -------------- - -This plugin is known to work with the following flavours of Vim: - - * Linux (tested on Ubuntu 12.04/12.10): - * vim/gvim (from vim-gnome package version 7.3) - - * Mac OS X (tested on Mountain Lion) - * Vim command-line (7.3 from Xcode) - * MacVim 7.3 - -To install the plugin, ensure you have - * a working version of lldb on your path, or the environment variable LLDB - pointing to the lldb binary you would like to use. - * a python-enabled vim (check with ":python print 2") - - -Installation ------------- - -1) Install the Vim pathogen plugin (it keeps installed plugins organized): - - https://github.com/tpope/vim-pathogen - - Or, for the impatient: - -mkdir -p ~/.vim/autoload ~/.vim/bundle; \ -curl -Sso ~/.vim/autoload/pathogen.vim \ - https://raw.github.com/tpope/vim-pathogen/master/autoload/pathogen.vim - -2) Symlink (or copy) ~/.vim/bundle/vim-lldb to this directory: - -ln -sf /utils/vim-lldb ~/.vim/bundle/vim-lldb - -3) Update your help-tags. Start vim, do: - - :Helptags - -4) Have fun! - - -Usage/Getting Help ------------------- -All LLDB commands (with tab-completion) can be accessed in Vim's -command mode. Try it out by typing: - -:L - -There are several sources of help available: - -:help lldb -- Documentation for this plugin -:Lhelp -- LLDB's built-in help system (i.e lldb 'help' command) -:Lscript help (lldb) -- Complete LLDB Python API reference Index: lldb/utils/vim-lldb/doc/lldb.txt =================================================================== --- lldb/utils/vim-lldb/doc/lldb.txt +++ /dev/null @@ -1,115 +0,0 @@ -*lldb.txt* A plugin that enables debugging from your favourite editor - -Author: Daniel Malea -License: Same terms as Vim itself (see |license|) - -INTRODUCTION *lldb* - -Installing this plugin enables a set of commands in Vim to control the -LLDB (http://lldb.llvm.org) debugger. - -COMMANDS *lldb-commands* - -The LLDB command interpreter is exposed to Vim's command mode using the -':L' prefix. Tab-completion is available and will cycle through commands. -Some commands have modified behaviour in Vim; for example, :Lbreakpoint -with no arguments will set a breakpoint at the current cursor, rather than -printing the standard help information for the LLDB command 'breakpoint'. - - *lldb-windows* - -In addition to the standard commands available under the LLDB interpreter, -there are also commands to display or hide informational debugger panes. - -Windows can be shown or hidden using the ':Lhide ' or ':Lshow ' -commands. - *lldb-:Lhide* -:Lhide [windowname] Hide informational debugger pane named 'windowname'. - - *lldb-:Lshow* -:Lshow [windowname] Show informational debugger pane named 'windowname'. - -Possible window name arguments to the Lhide and Lshow commands include: - - * backtrace - * breakpoints - * disassembly - * locals - * registers - * threads - *lldb-:Lattach* -:Lattach Attach to a process by name. - - *lldb-:Ldetach* -:Ldetach Detach from the current process. - - *lldb-:Ltarget* -:Ltarget [[create] executable] - Create a target with the specified executable. If - run with a single argument, that argument is assumed - to be a path to the executable to be debugged. - Otherwise, all arguments are passed into LLDB's command - interpreter. - - *lldb-:Lstart* -:Lstart Create a process by executing the current target - and wait for LLDB to attach. - - *lldb-:Lrun* -:Lrun Create a process by executing the current target - without waiting for LLDB to attach. - - *lldb-:Lcontinue* -:Lcontinue Continue execution of the process until the next - breakpoint is hit or the process exits. - - *lldb-:Lthread* -:Lthread Passes through to LLDB. See :Lhelp thread. - - *lldb-:Lstep* -:Lstep Step into the current function call. - - *lldb-:Lstepin* -:Lstepin Step into the current function call. - - *lldb-:Lstepinst* -:Lstepinst Step one instruction. - - *lldb-:Lstepinstover* -:Lstepinstover Step one instruction, but skip over jump or call - instructions. - - *lldb-:Lnext* -:Lnext Step to the next line. - - *lldb-:Lfinish* -:Lfinish Step out of the current function. - - *lldb-:Lbreakpoint* -:Lbreakpoint [args] When arguments are provided, the lldb breakpoint - command is invoked. If no arguments are provided, - a breakpoint at the location under the cursor. - - *lldb-:Lprint* - *lldb-:Lpo* - *lldb-:LpO* -:Lprint Aliases to the lldb print and po commands. Cursor -:Lpo word (cursor WORD for LpO) will be used when -:LpO expression omitted. - -MAPPINGS *lldb-mappings* - -On Mac OS X (under MacVim) , the following key mappings are available: - - Insert a breakpoint at the line under cursor - - -ABOUT *lldb-about* - -Grab the latest version of this plugin (and LLDB sources) with: - git clone https://github.com/llvm/llvm-project.git - -File any bugs at: - http://llvm.org/bugs/enter_bug.cgi?product=lldb - - vim:tw=78:et:ft=help:norl: Index: lldb/utils/vim-lldb/plugin/lldb.vim =================================================================== --- lldb/utils/vim-lldb/plugin/lldb.vim +++ /dev/null @@ -1,151 +0,0 @@ - -" Vim script glue code for LLDB integration - -function! s:FindPythonScriptDir() - for dir in pathogen#split(&runtimepath) - let searchstr = "python-vim-lldb" - let candidates = pathogen#glob_directories(dir . "/" . searchstr) - if len(candidates) > 0 - return candidates[0] - endif - endfor - return -endfunction() - -function! s:InitLldbPlugin() - if has('python') == 0 - call confirm('ERROR: This Vim installation does not have python support. lldb.vim will not work.') - return - endif - - " Key-Bindings - " FIXME: choose sensible keybindings for: - " - process: start, interrupt, continue, continue-to-cursor - " - step: instruction, in, over, out - " - if has('gui_macvim') - " Apple-B toggles breakpoint on cursor - map :Lbreakpoint - endif - - " - " Setup the python interpreter path - " - let vim_lldb_pydir = s:FindPythonScriptDir() - execute 'python import sys; sys.path.append("' . vim_lldb_pydir . '")' - - " - " Register :L - " The LLDB CommandInterpreter provides tab-completion in Vim's command mode. - " FIXME: this list of commands, at least partially should be auto-generated - " - - " Window show/hide commands - command -complete=custom,s:CompleteWindow -nargs=1 Lhide python ctrl.doHide('') - command -complete=custom,s:CompleteWindow -nargs=0 Lshow python ctrl.doShow('') - - " Launching convenience commands (no autocompletion) - command -nargs=* Lstart python ctrl.doLaunch(True, '') - command -nargs=* Lrun python ctrl.doLaunch(False, '') - command -nargs=1 Lattach python ctrl.doAttach('') - command -nargs=0 Ldetach python ctrl.doDetach() - - " Regexp-commands: because vim's command mode does not support '_' or '-' - " characters in command names, we omit them when creating the :L - " equivalents. - command -complete=custom,s:CompleteCommand -nargs=* Lregexpattach python ctrl.doCommand('_regexp-attach', '') - command -complete=custom,s:CompleteCommand -nargs=* Lregexpbreak python ctrl.doCommand('_regexp-break', '') - command -complete=custom,s:CompleteCommand -nargs=* Lregexpbt python ctrl.doCommand('_regexp-bt', '') - command -complete=custom,s:CompleteCommand -nargs=* Lregexpdown python ctrl.doCommand('_regexp-down', '') - command -complete=custom,s:CompleteCommand -nargs=* Lregexptbreak python ctrl.doCommand('_regexp-tbreak', '') - command -complete=custom,s:CompleteCommand -nargs=* Lregexpdisplay python ctrl.doCommand('_regexp-display', '') - command -complete=custom,s:CompleteCommand -nargs=* Lregexpundisplay python ctrl.doCommand('_regexp-undisplay', '') - command -complete=custom,s:CompleteCommand -nargs=* Lregexpup python ctrl.doCommand('_regexp-up', '') - - command -complete=custom,s:CompleteCommand -nargs=* Lapropos python ctrl.doCommand('apropos', '') - command -complete=custom,s:CompleteCommand -nargs=* Lbacktrace python ctrl.doCommand('bt', '') - command -complete=custom,s:CompleteCommand -nargs=* Lbreakpoint python ctrl.doBreakpoint('') - command -complete=custom,s:CompleteCommand -nargs=* Lcommand python ctrl.doCommand('command', '') - command -complete=custom,s:CompleteCommand -nargs=* Ldisassemble python ctrl.doCommand('disassemble', '') - command -complete=custom,s:CompleteCommand -nargs=* Lexpression python ctrl.doCommand('expression', '') - command -complete=custom,s:CompleteCommand -nargs=* Lhelp python ctrl.doCommand('help', '') - command -complete=custom,s:CompleteCommand -nargs=* Llog python ctrl.doCommand('log', '') - command -complete=custom,s:CompleteCommand -nargs=* Lplatform python ctrl.doCommand('platform','') - command -complete=custom,s:CompleteCommand -nargs=* Lplugin python ctrl.doCommand('plugin', '') - command -complete=custom,s:CompleteCommand -nargs=* Lprocess python ctrl.doProcess('') - command -complete=custom,s:CompleteCommand -nargs=* Lregister python ctrl.doCommand('register', '') - command -complete=custom,s:CompleteCommand -nargs=* Lscript python ctrl.doCommand('script', '') - command -complete=custom,s:CompleteCommand -nargs=* Lsettings python ctrl.doCommand('settings','') - command -complete=custom,s:CompleteCommand -nargs=* Lsource python ctrl.doCommand('source', '') - command -complete=custom,s:CompleteCommand -nargs=* Ltype python ctrl.doCommand('type', '') - command -complete=custom,s:CompleteCommand -nargs=* Lversion python ctrl.doCommand('version', '') - command -complete=custom,s:CompleteCommand -nargs=* Lwatchpoint python ctrl.doCommand('watchpoint', '') - - " Convenience (shortcut) LLDB commands - command -complete=custom,s:CompleteCommand -nargs=* Lprint python ctrl.doCommand('print', vim.eval("s:CursorWord('')")) - command -complete=custom,s:CompleteCommand -nargs=* Lpo python ctrl.doCommand('po', vim.eval("s:CursorWord('')")) - command -complete=custom,s:CompleteCommand -nargs=* LpO python ctrl.doCommand('po', vim.eval("s:CursorWORD('')")) - command -complete=custom,s:CompleteCommand -nargs=* Lbt python ctrl.doCommand('bt', '') - - " Frame/Thread-Selection (commands that also do an Uupdate but do not - " generate events in LLDB) - command -complete=custom,s:CompleteCommand -nargs=* Lframe python ctrl.doSelect('frame', '') - command -complete=custom,s:CompleteCommand -nargs=? Lup python ctrl.doCommand('up', '', print_on_success=False, goto_file=True) - command -complete=custom,s:CompleteCommand -nargs=? Ldown python ctrl.doCommand('down', '', print_on_success=False, goto_file=True) - command -complete=custom,s:CompleteCommand -nargs=* Lthread python ctrl.doSelect('thread', '') - - command -complete=custom,s:CompleteCommand -nargs=* Ltarget python ctrl.doTarget('') - - " Continue - command -complete=custom,s:CompleteCommand -nargs=* Lcontinue python ctrl.doContinue() - - " Thread-Stepping (no autocompletion) - command -nargs=0 Lstepinst python ctrl.doStep(StepType.INSTRUCTION) - command -nargs=0 Lstepinstover python ctrl.doStep(StepType.INSTRUCTION_OVER) - command -nargs=0 Lstepin python ctrl.doStep(StepType.INTO) - command -nargs=0 Lstep python ctrl.doStep(StepType.INTO) - command -nargs=0 Lnext python ctrl.doStep(StepType.OVER) - command -nargs=0 Lfinish python ctrl.doStep(StepType.OUT) - - " hack: service the LLDB event-queue when the cursor moves - " FIXME: some threaded solution would be better...but it - " would have to be designed carefully because Vim's APIs are non threadsafe; - " use of the vim module **MUST** be restricted to the main thread. - command -nargs=0 Lrefresh python ctrl.doRefresh() - autocmd CursorMoved * :Lrefresh - autocmd CursorHold * :Lrefresh - autocmd VimLeavePre * python ctrl.doExit() - - execute 'pyfile ' . vim_lldb_pydir . '/plugin.py' -endfunction() - -function! s:CompleteCommand(A, L, P) - python << EOF -a = vim.eval("a:A") -l = vim.eval("a:L") -p = vim.eval("a:P") -returnCompleteCommand(a, l, p) -EOF -endfunction() - -function! s:CompleteWindow(A, L, P) - python << EOF -a = vim.eval("a:A") -l = vim.eval("a:L") -p = vim.eval("a:P") -returnCompleteWindow(a, l, p) -EOF -endfunction() - -" Returns cword if search term is empty -function! s:CursorWord(term) - return empty(a:term) ? expand('') : a:term -endfunction() - -" Returns cleaned cWORD if search term is empty -function! s:CursorWORD(term) - " Will strip all non-alphabetic characters from both sides - return empty(a:term) ? substitute(expand(''), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term -endfunction() - -call s:InitLldbPlugin() Index: lldb/utils/vim-lldb/python-vim-lldb/import_lldb.py =================================================================== --- lldb/utils/vim-lldb/python-vim-lldb/import_lldb.py +++ /dev/null @@ -1,71 +0,0 @@ - -# Locate and load the lldb python module - -import os -import sys - - -def import_lldb(): - """ Find and import the lldb modules. This function tries to find the lldb module by: - 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, - 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb - on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid - path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the - default Xcode 4.5 installation path. - """ - - # Try simple 'import lldb', in case of a system-wide install or a - # pre-configured PYTHONPATH - try: - import lldb - return True - except ImportError: - pass - - # Allow overriding default path to lldb executable with the LLDB - # environment variable - lldb_executable = 'lldb' - if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): - lldb_executable = os.environ['LLDB'] - - # Try using builtin module location support ('lldb -P') - from subprocess import check_output, CalledProcessError - try: - with open(os.devnull, 'w') as fnull: - lldb_minus_p_path = check_output( - "%s -P" % - lldb_executable, - shell=True, - stderr=fnull).strip() - if not os.path.exists(lldb_minus_p_path): - # lldb -P returned invalid path, probably too old - pass - else: - sys.path.append(lldb_minus_p_path) - import lldb - return True - except CalledProcessError: - # Cannot run 'lldb -P' to determine location of lldb python module - pass - except ImportError: - # Unable to import lldb module from path returned by `lldb -P` - pass - - # On Mac OS X, use the try the default path to XCode lldb module - if "darwin" in sys.platform: - xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" - sys.path.append(xcode_python_path) - try: - import lldb - return True - except ImportError: - # Unable to import lldb module from default Xcode python path - pass - - return False - -if not import_lldb(): - import vim - vim.command( - 'redraw | echo "%s"' % - " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") Index: lldb/utils/vim-lldb/python-vim-lldb/lldb_controller.py =================================================================== --- lldb/utils/vim-lldb/python-vim-lldb/lldb_controller.py +++ /dev/null @@ -1,415 +0,0 @@ - -# -# This file defines the layer that talks to lldb -# - -from __future__ import print_function - -import os -import re -import sys -import lldb -import vim -from vim_ui import UI - -# ================================================= -# Convert some enum value to its string counterpart -# ================================================= - -# Shamelessly copy/pasted from lldbutil.py in the test suite - - -def state_type_to_str(enum): - """Returns the stateType string given an enum.""" - if enum == lldb.eStateInvalid: - return "invalid" - elif enum == lldb.eStateUnloaded: - return "unloaded" - elif enum == lldb.eStateConnected: - return "connected" - elif enum == lldb.eStateAttaching: - return "attaching" - elif enum == lldb.eStateLaunching: - return "launching" - elif enum == lldb.eStateStopped: - return "stopped" - elif enum == lldb.eStateRunning: - return "running" - elif enum == lldb.eStateStepping: - return "stepping" - elif enum == lldb.eStateCrashed: - return "crashed" - elif enum == lldb.eStateDetached: - return "detached" - elif enum == lldb.eStateExited: - return "exited" - elif enum == lldb.eStateSuspended: - return "suspended" - else: - raise Exception("Unknown StateType enum") - - -class StepType: - INSTRUCTION = 1 - INSTRUCTION_OVER = 2 - INTO = 3 - OVER = 4 - OUT = 5 - - -class LLDBController(object): - """ Handles Vim and LLDB events such as commands and lldb events. """ - - # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to - # servicing LLDB events from the main UI thread. Usually, we only process events that are already - # sitting on the queue. But in some situations (when we are expecting an event as a result of some - # user interaction) we want to wait for it. The constants below set these wait period in which the - # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher - # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at - # times. - eventDelayStep = 2 - eventDelayLaunch = 1 - eventDelayContinue = 1 - - def __init__(self): - """ Creates the LLDB SBDebugger object and initializes the UI class. """ - self.target = None - self.process = None - self.load_dependent_modules = True - - self.dbg = lldb.SBDebugger.Create() - self.commandInterpreter = self.dbg.GetCommandInterpreter() - - self.ui = UI() - - def completeCommand(self, a, l, p): - """ Returns a list of viable completions for command a with length l and cursor at p """ - - assert l[0] == 'L' - # Remove first 'L' character that all commands start with - l = l[1:] - - # Adjust length as string has 1 less character - p = int(p) - 1 - - result = lldb.SBStringList() - num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) - - if num == -1: - # FIXME: insert completion character... what's a completion - # character? - pass - elif num == -2: - # FIXME: replace line with result.GetStringAtIndex(0) - pass - - if result.GetSize() > 0: - results = [_f for _f in [result.GetStringAtIndex(x) - for x in range(result.GetSize())] if _f] - return results - else: - return [] - - def doStep(self, stepType): - """ Perform a step command and block the UI for eventDelayStep seconds in order to process - events on lldb's event queue. - FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to - the main thread to avoid the appearance of a "hang". If this happens, the UI will - update whenever; usually when the user moves the cursor. This is somewhat annoying. - """ - if not self.process: - sys.stderr.write("No process to step") - return - - t = self.process.GetSelectedThread() - if stepType == StepType.INSTRUCTION: - t.StepInstruction(False) - if stepType == StepType.INSTRUCTION_OVER: - t.StepInstruction(True) - elif stepType == StepType.INTO: - t.StepInto() - elif stepType == StepType.OVER: - t.StepOver() - elif stepType == StepType.OUT: - t.StepOut() - - self.processPendingEvents(self.eventDelayStep, True) - - def doSelect(self, command, args): - """ Like doCommand, but suppress output when "select" is the first argument.""" - a = args.split(' ') - return self.doCommand(command, args, "select" != a[0], True) - - def doProcess(self, args): - """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead - of the command interpreter to start the inferior process. - """ - a = args.split(' ') - if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): - self.doCommand("process", args) - #self.ui.update(self.target, "", self) - else: - self.doLaunch('-s' not in args, "") - - def doAttach(self, process_name): - """ Handle process attach. """ - error = lldb.SBError() - - self.processListener = lldb.SBListener("process_event_listener") - self.target = self.dbg.CreateTarget('') - self.process = self.target.AttachToProcessWithName( - self.processListener, process_name, False, error) - if not error.Success(): - sys.stderr.write("Error during attach: " + str(error)) - return - - self.ui.activate() - self.pid = self.process.GetProcessID() - - print("Attached to %s (pid=%d)" % (process_name, self.pid)) - - def doDetach(self): - if self.process is not None and self.process.IsValid(): - pid = self.process.GetProcessID() - state = state_type_to_str(self.process.GetState()) - self.process.Detach() - self.processPendingEvents(self.eventDelayLaunch) - - def doLaunch(self, stop_at_entry, args): - """ Handle process launch. """ - error = lldb.SBError() - - fs = self.target.GetExecutable() - exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) - if self.process is not None and self.process.IsValid(): - pid = self.process.GetProcessID() - state = state_type_to_str(self.process.GetState()) - self.process.Destroy() - - launchInfo = lldb.SBLaunchInfo(args.split(' ')) - self.process = self.target.Launch(launchInfo, error) - if not error.Success(): - sys.stderr.write("Error during launch: " + str(error)) - return - - # launch succeeded, store pid and add some event listeners - self.pid = self.process.GetProcessID() - self.processListener = lldb.SBListener("process_event_listener") - self.process.GetBroadcaster().AddListener( - self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) - - print("Launched %s %s (pid=%d)" % (exe, args, self.pid)) - - if not stop_at_entry: - self.doContinue() - else: - self.processPendingEvents(self.eventDelayLaunch) - - def doTarget(self, args): - """ Pass target command to interpreter, except if argument is not one of the valid options, or - is create, in which case try to create a target with the argument as the executable. For example: - target list ==> handled by interpreter - target create blah ==> custom creation of target 'blah' - target blah ==> also creates target blah - """ - target_args = [ # "create", - "delete", - "list", - "modules", - "select", - "stop-hook", - "symbols", - "variable"] - - a = args.split(' ') - if len(args) == 0 or (len(a) > 0 and a[0] in target_args): - self.doCommand("target", args) - return - elif len(a) > 1 and a[0] == "create": - exe = a[1] - elif len(a) == 1 and a[0] not in target_args: - exe = a[0] - - err = lldb.SBError() - self.target = self.dbg.CreateTarget( - exe, None, None, self.load_dependent_modules, err) - if not self.target: - sys.stderr.write( - "Error creating target %s. %s" % - (str(exe), str(err))) - return - - self.ui.activate() - self.ui.update(self.target, "created target %s" % str(exe), self) - - def doContinue(self): - """ Handle 'contiue' command. - FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. - """ - if not self.process or not self.process.IsValid(): - sys.stderr.write("No process to continue") - return - - self.process.Continue() - self.processPendingEvents(self.eventDelayContinue) - - def doBreakpoint(self, args): - """ Handle breakpoint command with command interpreter, except if the user calls - "breakpoint" with no other args, in which case add a breakpoint at the line - under the cursor. - """ - a = args.split(' ') - if len(args) == 0: - show_output = False - - # User called us with no args, so toggle the bp under cursor - cw = vim.current.window - cb = vim.current.buffer - name = cb.name - line = cw.cursor[0] - - # Since the UI is responsbile for placing signs at bp locations, we have to - # ask it if there already is one or more breakpoints at (file, - # line)... - if self.ui.haveBreakpoint(name, line): - bps = self.ui.getBreakpoints(name, line) - args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) - self.ui.deleteBreakpoints(name, line) - else: - args = "set -f %s -l %d" % (name, line) - else: - show_output = True - - self.doCommand("breakpoint", args, show_output) - return - - def doRefresh(self): - """ process pending events and update UI on request """ - status = self.processPendingEvents() - - def doShow(self, name): - """ handle :Lshow """ - if not name: - self.ui.activate() - return - - if self.ui.showWindow(name): - self.ui.update(self.target, "", self) - - def doHide(self, name): - """ handle :Lhide """ - if self.ui.hideWindow(name): - self.ui.update(self.target, "", self) - - def doExit(self): - self.dbg.Terminate() - self.dbg = None - - def getCommandResult(self, command, command_args): - """ Run cmd in the command interpreter and returns (success, output) """ - result = lldb.SBCommandReturnObject() - cmd = "%s %s" % (command, command_args) - - self.commandInterpreter.HandleCommand(cmd, result) - return (result.Succeeded(), result.GetOutput() - if result.Succeeded() else result.GetError()) - - def doCommand( - self, - command, - command_args, - print_on_success=True, - goto_file=False): - """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ - (success, output) = self.getCommandResult(command, command_args) - if success: - self.ui.update(self.target, "", self, goto_file) - if len(output) > 0 and print_on_success: - print(output) - else: - sys.stderr.write(output) - - def getCommandOutput(self, command, command_args=""): - """ runs cmd in the command interpreter andreturns (status, result) """ - result = lldb.SBCommandReturnObject() - cmd = "%s %s" % (command, command_args) - self.commandInterpreter.HandleCommand(cmd, result) - return (result.Succeeded(), result.GetOutput() - if result.Succeeded() else result.GetError()) - - def processPendingEvents(self, wait_seconds=0, goto_file=True): - """ Handle any events that are queued from the inferior. - Blocks for at most wait_seconds, or if wait_seconds == 0, - process only events that are already queued. - """ - - status = None - num_events_handled = 0 - - if self.process is not None: - event = lldb.SBEvent() - old_state = self.process.GetState() - new_state = None - done = False - if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: - # Early-exit if we are in 'boring' states - pass - else: - while not done and self.processListener is not None: - if not self.processListener.PeekAtNextEvent(event): - if wait_seconds > 0: - # No events on the queue, but we are allowed to wait for wait_seconds - # for any events to show up. - self.processListener.WaitForEvent( - wait_seconds, event) - new_state = lldb.SBProcess.GetStateFromEvent(event) - - num_events_handled += 1 - - done = not self.processListener.PeekAtNextEvent(event) - else: - # An event is on the queue, process it here. - self.processListener.GetNextEvent(event) - new_state = lldb.SBProcess.GetStateFromEvent(event) - - # continue if stopped after attaching - if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: - self.process.Continue() - - # If needed, perform any event-specific behaviour here - num_events_handled += 1 - - if num_events_handled == 0: - pass - else: - if old_state == new_state: - status = "" - self.ui.update(self.target, status, self, goto_file) - - -def returnCompleteCommand(a, l, p): - """ Returns a "\n"-separated string with possible completion results - for command a with length l and cursor at p. - """ - separator = "\n" - results = ctrl.completeCommand(a, l, p) - vim.command('return "%s%s"' % (separator.join(results), separator)) - - -def returnCompleteWindow(a, l, p): - """ Returns a "\n"-separated string with possible completion results - for commands that expect a window name parameter (like hide/show). - FIXME: connect to ctrl.ui instead of hardcoding the list here - """ - separator = "\n" - results = [ - 'breakpoints', - 'backtrace', - 'disassembly', - 'locals', - 'threads', - 'registers'] - vim.command('return "%s%s"' % (separator.join(results), separator)) - -global ctrl -ctrl = LLDBController() Index: lldb/utils/vim-lldb/python-vim-lldb/plugin.py =================================================================== --- lldb/utils/vim-lldb/python-vim-lldb/plugin.py +++ /dev/null @@ -1,16 +0,0 @@ - -# Try to import all dependencies, catch and handle the error gracefully if -# it fails. - -import import_lldb - -try: - import lldb - import vim -except ImportError: - sys.stderr.write( - "Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") - pass -else: - # Everthing went well, so use import to start the plugin controller - from lldb_controller import * Index: lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py =================================================================== --- lldb/utils/vim-lldb/python-vim-lldb/vim_panes.py +++ /dev/null @@ -1,669 +0,0 @@ -# -# This file contains implementations of the LLDB display panes in VIM -# -# The most generic way to define a new window is to inherit from VimPane -# and to implement: -# - get_content() - returns a string with the pane contents -# -# Optionally, to highlight text, implement: -# - get_highlights() - returns a map -# -# And call: -# - define_highlight(unique_name, colour) -# at some point in the constructor. -# -# -# If the pane shows some key-value data that is in the context of a -# single frame, inherit from FrameKeyValuePane and implement: -# - get_frame_content(self, SBFrame frame) -# -# -# If the pane presents some information that can be retrieved with -# a simple LLDB command while the subprocess is stopped, inherit -# from StoppedCommandPane and call: -# - self.setCommand(command, command_args) -# at some point in the constructor. -# -# Optionally, you can implement: -# - get_selected_line() -# to highlight a selected line and place the cursor there. -# -# -# FIXME: implement WatchlistPane to displayed watched expressions -# FIXME: define interface for interactive panes, like catching enter -# presses to change selected frame/thread... -# - -import lldb -import vim - -import sys - -# ============================================================== -# Get the description of an lldb object or None if not available -# ============================================================== - -# Shamelessly copy/pasted from lldbutil.py in the test suite - - -def get_description(obj, option=None): - """Calls lldb_obj.GetDescription() and returns a string, or None. - - For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra - option can be passed in to describe the detailed level of description - desired: - o lldb.eDescriptionLevelBrief - o lldb.eDescriptionLevelFull - o lldb.eDescriptionLevelVerbose - """ - method = getattr(obj, 'GetDescription') - if not method: - return None - tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) - if isinstance(obj, tuple): - if option is None: - option = lldb.eDescriptionLevelBrief - - stream = lldb.SBStream() - if option is None: - success = method(stream) - else: - success = method(stream, option) - if not success: - return None - return stream.GetData() - - -def get_selected_thread(target): - """ Returns a tuple with (thread, error) where thread == None if error occurs """ - process = target.GetProcess() - if process is None or not process.IsValid(): - return (None, VimPane.MSG_NO_PROCESS) - - thread = process.GetSelectedThread() - if thread is None or not thread.IsValid(): - return (None, VimPane.MSG_NO_THREADS) - return (thread, "") - - -def get_selected_frame(target): - """ Returns a tuple with (frame, error) where frame == None if error occurs """ - (thread, error) = get_selected_thread(target) - if thread is None: - return (None, error) - - frame = thread.GetSelectedFrame() - if frame is None or not frame.IsValid(): - return (None, VimPane.MSG_NO_FRAME) - return (frame, "") - - -def _cmd(cmd): - vim.command("call confirm('%s')" % cmd) - vim.command(cmd) - - -def move_cursor(line, col=0): - """ moves cursor to specified line and col """ - cw = vim.current.window - if cw.cursor[0] != line: - vim.command("execute \"normal %dgg\"" % line) - - -def winnr(): - """ Returns currently selected window number """ - return int(vim.eval("winnr()")) - - -def bufwinnr(name): - """ Returns window number corresponding with buffer name """ - return int(vim.eval("bufwinnr('%s')" % name)) - - -def goto_window(nr): - """ go to window number nr""" - if nr != winnr(): - vim.command(str(nr) + ' wincmd w') - - -def goto_next_window(): - """ go to next window. """ - vim.command('wincmd w') - return (winnr(), vim.current.buffer.name) - - -def goto_previous_window(): - """ go to previously selected window """ - vim.command("execute \"normal \\p\"") - - -def have_gui(): - """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ - return int(vim.eval("has('gui_running')")) == 1 - - -class PaneLayout(object): - """ A container for a (vertical) group layout of VimPanes """ - - def __init__(self): - self.panes = {} - - def havePane(self, name): - """ Returns true if name is a registered pane, False otherwise """ - return name in self.panes - - def prepare(self, panes=[]): - """ Draw panes on screen. If empty list is provided, show all. """ - - # If we can't select a window contained in the layout, we are doing a - # first draw - first_draw = not self.selectWindow(True) - did_first_draw = False - - # Prepare each registered pane - for name in self.panes: - if name in panes or len(panes) == 0: - if first_draw: - # First window in layout will be created with :vsp, and - # closed later - vim.command(":vsp") - first_draw = False - did_first_draw = True - self.panes[name].prepare() - - if did_first_draw: - # Close the split window - vim.command(":q") - - self.selectWindow(False) - - def contains(self, bufferName=None): - """ Returns True if window with name bufferName is contained in the layout, False otherwise. - If bufferName is None, the currently selected window is checked. - """ - if not bufferName: - bufferName = vim.current.buffer.name - - for p in self.panes: - if bufferName is not None and bufferName.endswith(p): - return True - return False - - def selectWindow(self, select_contained=True): - """ Selects a window contained in the layout (if select_contained = True) and returns True. - If select_contained = False, a window that is not contained is selected. Returns False - if no group windows can be selected. - """ - if select_contained == self.contains(): - # Simple case: we are already selected - return True - - # Otherwise, switch to next window until we find a contained window, or - # reach the first window again. - first = winnr() - (curnum, curname) = goto_next_window() - - while not select_contained == self.contains( - curname) and curnum != first: - (curnum, curname) = goto_next_window() - - return self.contains(curname) == select_contained - - def hide(self, panes=[]): - """ Hide panes specified. If empty list provided, hide all. """ - for name in self.panes: - if name in panes or len(panes) == 0: - self.panes[name].destroy() - - def registerForUpdates(self, p): - self.panes[p.name] = p - - def update(self, target, controller): - for name in self.panes: - self.panes[name].update(target, controller) - - -class VimPane(object): - """ A generic base class for a pane that displays stuff """ - CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' - CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' - CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' - - SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' - SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' - SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' - - MSG_NO_TARGET = "Target does not exist." - MSG_NO_PROCESS = "Process does not exist." - MSG_NO_THREADS = "No valid threads." - MSG_NO_FRAME = "No valid frame." - - # list of defined highlights, so we avoid re-defining them - highlightTypes = [] - - def __init__(self, owner, name, open_below=False, height=3): - self.owner = owner - self.name = name - self.buffer = None - self.maxHeight = 20 - self.openBelow = open_below - self.height = height - self.owner.registerForUpdates(self) - - def isPrepared(self): - """ check window is OK """ - if self.buffer is None or len( - dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: - return False - return True - - def prepare(self, method='new'): - """ check window is OK, if not then create """ - if not self.isPrepared(): - self.create(method) - - def on_create(self): - pass - - def destroy(self): - """ destroy window """ - if self.buffer is None or len(dir(self.buffer)) == 0: - return - vim.command('bdelete ' + self.name) - - def create(self, method): - """ create window """ - - if method != 'edit': - belowcmd = "below" if self.openBelow else "" - vim.command('silent %s %s %s' % (belowcmd, method, self.name)) - else: - vim.command('silent %s %s' % (method, self.name)) - - self.window = vim.current.window - - # Set LLDB pane options - vim.command("setlocal buftype=nofile") # Don't try to open a file - vim.command("setlocal noswapfile") # Don't use a swap file - vim.command("set nonumber") # Don't display line numbers - # vim.command("set nowrap") # Don't wrap text - - # Save some parameters and reference to buffer - self.buffer = vim.current.buffer - self.width = int(vim.eval("winwidth(0)")) - self.height = int(vim.eval("winheight(0)")) - - self.on_create() - goto_previous_window() - - def update(self, target, controller): - """ updates buffer contents """ - self.target = target - if not self.isPrepared(): - # Window is hidden, or otherwise not ready for an update - return - - original_cursor = self.window.cursor - - # Select pane - goto_window(bufwinnr(self.name)) - - # Clean and update content, and apply any highlights. - self.clean() - - if self.write(self.get_content(target, controller)): - self.apply_highlights() - - cursor = self.get_selected_line() - if cursor is None: - # Place the cursor at its original position in the window - cursor_line = min(original_cursor[0], len(self.buffer)) - cursor_col = min( - original_cursor[1], len( - self.buffer[ - cursor_line - 1])) - else: - # Place the cursor at the location requested by a VimPane - # implementation - cursor_line = min(cursor, len(self.buffer)) - cursor_col = self.window.cursor[1] - - self.window.cursor = (cursor_line, cursor_col) - - goto_previous_window() - - def get_selected_line(self): - """ Returns the line number to move the cursor to, or None to leave - it where the user last left it. - Subclasses implement this to define custom behaviour. - """ - return None - - def apply_highlights(self): - """ Highlights each set of lines in each highlight group """ - highlights = self.get_highlights() - for highlightType in highlights: - lines = highlights[highlightType] - if len(lines) == 0: - continue - - cmd = 'match %s /' % highlightType - lines = ['\%' + '%d' % line + 'l' for line in lines] - cmd += '\\|'.join(lines) - cmd += '/' - vim.command(cmd) - - def define_highlight(self, name, colour): - """ Defines highlihght """ - if name in VimPane.highlightTypes: - # highlight already defined - return - - vim.command( - "highlight %s ctermbg=%s guibg=%s" % - (name, colour, colour)) - VimPane.highlightTypes.append(name) - - def write(self, msg): - """ replace buffer with msg""" - self.prepare() - - msg = str(msg.encode("utf-8", "replace")).split('\n') - try: - self.buffer.append(msg) - vim.command("execute \"normal ggdd\"") - except vim.error: - # cannot update window; happens when vim is exiting. - return False - - move_cursor(1, 0) - return True - - def clean(self): - """ clean all datas in buffer """ - self.prepare() - vim.command(':%d') - #self.buffer[:] = None - - def get_content(self, target, controller): - """ subclasses implement this to provide pane content """ - assert(0 and "pane subclass must implement this") - pass - - def get_highlights(self): - """ Subclasses implement this to provide pane highlights. - This function is expected to return a map of: - { highlight_name ==> [line_number, ...], ... } - """ - return {} - - -class FrameKeyValuePane(VimPane): - - def __init__(self, owner, name, open_below): - """ Initialize parent, define member variables, choose which highlight - to use based on whether or not we have a gui (MacVim/Gvim). - """ - - VimPane.__init__(self, owner, name, open_below) - - # Map-of-maps key/value history { frame --> { variable_name, - # variable_value } } - self.frameValues = {} - - if have_gui(): - self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI - else: - self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM - self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, - VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) - - def format_pair(self, key, value, changed=False): - """ Formats a key/value pair. Appends a '*' if changed == True """ - marker = '*' if changed else ' ' - return "%s %s = %s\n" % (marker, key, value) - - def get_content(self, target, controller): - """ Get content for a frame-aware pane. Also builds the list of lines that - need highlighting (i.e. changed values.) - """ - if target is None or not target.IsValid(): - return VimPane.MSG_NO_TARGET - - self.changedLines = [] - - (frame, err) = get_selected_frame(target) - if frame is None: - return err - - output = get_description(frame) - lineNum = 1 - - # Retrieve the last values displayed for this frame - frameId = get_description(frame.GetBlock()) - if frameId in self.frameValues: - frameOldValues = self.frameValues[frameId] - else: - frameOldValues = {} - - # Read the frame variables - vals = self.get_frame_content(frame) - for (key, value) in vals: - lineNum += 1 - if len(frameOldValues) == 0 or ( - key in frameOldValues and frameOldValues[key] == value): - output += self.format_pair(key, value) - else: - output += self.format_pair(key, value, True) - self.changedLines.append(lineNum) - - # Save values as oldValues - newValues = {} - for (key, value) in vals: - newValues[key] = value - self.frameValues[frameId] = newValues - - return output - - def get_highlights(self): - ret = {} - ret[self.changedHighlight] = self.changedLines - return ret - - -class LocalsPane(FrameKeyValuePane): - """ Pane that displays local variables """ - - def __init__(self, owner, name='locals'): - FrameKeyValuePane.__init__(self, owner, name, open_below=True) - - # FIXME: allow users to customize display of args/locals/statics/scope - self.arguments = True - self.show_locals = True - self.show_statics = True - self.show_in_scope_only = True - - def format_variable(self, var): - """ Returns a Tuple of strings "(Type) Name", "Value" for SBValue var """ - val = var.GetValue() - if val is None: - # If the value is too big, SBValue.GetValue() returns None; replace - # with ... - val = "..." - - return ("(%s) %s" % (var.GetTypeName(), var.GetName()), "%s" % val) - - def get_frame_content(self, frame): - """ Returns list of key-value pairs of local variables in frame """ - vals = frame.GetVariables(self.arguments, - self.show_locals, - self.show_statics, - self.show_in_scope_only) - return [self.format_variable(x) for x in vals] - - -class RegistersPane(FrameKeyValuePane): - """ Pane that displays the contents of registers """ - - def __init__(self, owner, name='registers'): - FrameKeyValuePane.__init__(self, owner, name, open_below=True) - - def format_register(self, reg): - """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ - name = reg.GetName() - val = reg.GetValue() - if val is None: - val = "..." - return (name, val.strip()) - - def get_frame_content(self, frame): - """ Returns a list of key-value pairs ("name", "value") of registers in frame """ - - result = [] - for register_sets in frame.GetRegisters(): - # hack the register group name into the list of registers... - result.append((" = = %s =" % register_sets.GetName(), "")) - - for reg in register_sets: - result.append(self.format_register(reg)) - return result - - -class CommandPane(VimPane): - """ Pane that displays the output of an LLDB command """ - - def __init__(self, owner, name, open_below, process_required=True): - VimPane.__init__(self, owner, name, open_below) - self.process_required = process_required - - def setCommand(self, command, args=""): - self.command = command - self.args = args - - def get_content(self, target, controller): - output = "" - if not target: - output = VimPane.MSG_NO_TARGET - elif self.process_required and not target.GetProcess(): - output = VimPane.MSG_NO_PROCESS - else: - (success, output) = controller.getCommandOutput( - self.command, self.args) - return output - - -class StoppedCommandPane(CommandPane): - """ Pane that displays the output of an LLDB command when the process is - stopped; otherwise displays process status. This class also implements - highlighting for a single line (to show a single-line selected entity.) - """ - - def __init__(self, owner, name, open_below): - """ Initialize parent and define highlight to use for selected line. """ - CommandPane.__init__(self, owner, name, open_below) - if have_gui(): - self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI - else: - self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM - self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, - VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) - - def get_content(self, target, controller): - """ Returns the output of a command that relies on the process being stopped. - If the process is not in 'stopped' state, the process status is returned. - """ - output = "" - if not target or not target.IsValid(): - output = VimPane.MSG_NO_TARGET - elif not target.GetProcess() or not target.GetProcess().IsValid(): - output = VimPane.MSG_NO_PROCESS - elif target.GetProcess().GetState() == lldb.eStateStopped: - (success, output) = controller.getCommandOutput( - self.command, self.args) - else: - (success, output) = controller.getCommandOutput("process", "status") - return output - - def get_highlights(self): - """ Highlight the line under the cursor. Users moving the cursor has - no effect on the selected line. - """ - ret = {} - line = self.get_selected_line() - if line is not None: - ret[self.selectedHighlight] = [line] - return ret - return ret - - def get_selected_line(self): - """ Subclasses implement this to control where the cursor (and selected highlight) - is placed. - """ - return None - - -class DisassemblyPane(CommandPane): - """ Pane that displays disassembly around PC """ - - def __init__(self, owner, name='disassembly'): - CommandPane.__init__(self, owner, name, open_below=True) - - # FIXME: let users customize the number of instructions to disassemble - self.setCommand("disassemble", "-c %d -p" % self.maxHeight) - - -class ThreadPane(StoppedCommandPane): - """ Pane that displays threads list """ - - def __init__(self, owner, name='threads'): - StoppedCommandPane.__init__(self, owner, name, open_below=False) - self.setCommand("thread", "list") - -# FIXME: the function below assumes threads are listed in sequential order, -# which turns out to not be the case. Highlighting of selected thread -# will be disabled until this can be fixed. LLDB prints a '*' anyways -# beside the selected thread, so this is not too big of a problem. -# def get_selected_line(self): -# """ Place the cursor on the line with the selected entity. -# Subclasses should override this to customize selection. -# Formula: selected_line = selected_thread_id + 1 -# """ -# (thread, err) = get_selected_thread(self.target) -# if thread is None: -# return None -# else: -# return thread.GetIndexID() + 1 - - -class BacktracePane(StoppedCommandPane): - """ Pane that displays backtrace """ - - def __init__(self, owner, name='backtrace'): - StoppedCommandPane.__init__(self, owner, name, open_below=False) - self.setCommand("bt", "") - - def get_selected_line(self): - """ Returns the line number in the buffer with the selected frame. - Formula: selected_line = selected_frame_id + 2 - FIXME: the above formula hack does not work when the function return - value is printed in the bt window; the wrong line is highlighted. - """ - - (frame, err) = get_selected_frame(self.target) - if frame is None: - return None - else: - return frame.GetFrameID() + 2 - - -class BreakpointsPane(CommandPane): - - def __init__(self, owner, name='breakpoints'): - super( - BreakpointsPane, - self).__init__( - owner, - name, - open_below=False, - process_required=False) - self.setCommand("breakpoint", "list") Index: lldb/utils/vim-lldb/python-vim-lldb/vim_signs.py =================================================================== --- lldb/utils/vim-lldb/python-vim-lldb/vim_signs.py +++ /dev/null @@ -1,81 +0,0 @@ - -# Classes responsible for drawing signs in the Vim user interface. - -import vim - - -class VimSign(object): - SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" - SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" - SIGN_TEXT_PC = "->" - SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' - - # unique sign id (for ':[sign/highlight] define) - sign_id = 1 - - # unique name id (for ':sign place') - name_id = 1 - - # Map of {(sign_text, highlight_colour) --> sign_name} - defined_signs = {} - - def __init__(self, sign_text, buffer, line_number, highlight_colour=None): - """ Define the sign and highlight (if applicable) and show the sign. """ - - # Get the sign name, either by defining it, or looking it up in the map - # of defined signs - key = (sign_text, highlight_colour) - if key not in VimSign.defined_signs: - name = self.define(sign_text, highlight_colour) - else: - name = VimSign.defined_signs[key] - - self.show(name, buffer.number, line_number) - pass - - def define(self, sign_text, highlight_colour): - """ Defines sign and highlight (if highlight_colour is not None). """ - sign_name = "sign%d" % VimSign.name_id - if highlight_colour is None: - vim.command("sign define %s text=%s" % (sign_name, sign_text)) - else: - self.highlight_name = "highlight%d" % VimSign.name_id - vim.command( - "highlight %s ctermbg=%s guibg=%s" % - (self.highlight_name, highlight_colour, highlight_colour)) - vim.command( - "sign define %s text=%s linehl=%s texthl=%s" % - (sign_name, sign_text, self.highlight_name, self.highlight_name)) - VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name - VimSign.name_id += 1 - return sign_name - - def show(self, name, buffer_number, line_number): - self.id = VimSign.sign_id - VimSign.sign_id += 1 - vim.command("sign place %d name=%s line=%d buffer=%s" % - (self.id, name, line_number, buffer_number)) - pass - - def hide(self): - vim.command("sign unplace %d" % self.id) - pass - - -class BreakpointSign(VimSign): - - def __init__(self, buffer, line_number, is_resolved): - txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED - super(BreakpointSign, self).__init__(txt, buffer, line_number) - - -class PCSign(VimSign): - - def __init__(self, buffer, line_number, is_selected_thread): - super( - PCSign, - self).__init__( - VimSign.SIGN_TEXT_PC, - buffer, - line_number, - VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) Index: lldb/utils/vim-lldb/python-vim-lldb/vim_ui.py =================================================================== --- lldb/utils/vim-lldb/python-vim-lldb/vim_ui.py +++ /dev/null @@ -1,257 +0,0 @@ - -# LLDB UI state in the Vim user interface. - -from __future__ import print_function - -import os -import re -import sys -import lldb -import vim -from vim_panes import * -from vim_signs import * - - -def is_same_file(a, b): - """ returns true if paths a and b are the same file """ - a = os.path.realpath(a) - b = os.path.realpath(b) - return a in b or b in a - - -class UI: - - def __init__(self): - """ Declare UI state variables """ - - # Default panes to display - self.defaultPanes = [ - 'breakpoints', - 'backtrace', - 'locals', - 'threads', - 'registers', - 'disassembly'] - - # map of tuples (filename, line) --> SBBreakpoint - self.markedBreakpoints = {} - - # Currently shown signs - self.breakpointSigns = {} - self.pcSigns = [] - - # Container for panes - self.paneCol = PaneLayout() - - # All possible LLDB panes - self.backtracePane = BacktracePane(self.paneCol) - self.threadPane = ThreadPane(self.paneCol) - self.disassemblyPane = DisassemblyPane(self.paneCol) - self.localsPane = LocalsPane(self.paneCol) - self.registersPane = RegistersPane(self.paneCol) - self.breakPane = BreakpointsPane(self.paneCol) - - def activate(self): - """ Activate UI: display default set of panes """ - self.paneCol.prepare(self.defaultPanes) - - def get_user_buffers(self, filter_name=None): - """ Returns a list of buffers that are not a part of the LLDB UI. That is, they - are not contained in the PaneLayout object self.paneCol. - """ - ret = [] - for w in vim.windows: - b = w.buffer - if not self.paneCol.contains(b.name): - if filter_name is None or filter_name in b.name: - ret.append(b) - return ret - - def update_pc(self, process, buffers, goto_file): - """ Place the PC sign on the PC location of each thread's selected frame """ - - def GetPCSourceLocation(thread): - """ Returns a tuple (thread_index, file, line, column) that represents where - the PC sign should be placed for a thread. - """ - - frame = thread.GetSelectedFrame() - frame_num = frame.GetFrameID() - le = frame.GetLineEntry() - while not le.IsValid() and frame_num < thread.GetNumFrames(): - frame_num += 1 - le = thread.GetFrameAtIndex(frame_num).GetLineEntry() - - if le.IsValid(): - path = os.path.join( - le.GetFileSpec().GetDirectory(), - le.GetFileSpec().GetFilename()) - return ( - thread.GetIndexID(), - path, - le.GetLine(), - le.GetColumn()) - return None - - # Clear all existing PC signs - del_list = [] - for sign in self.pcSigns: - sign.hide() - del_list.append(sign) - for sign in del_list: - self.pcSigns.remove(sign) - del sign - - # Select a user (non-lldb) window - if not self.paneCol.selectWindow(False): - # No user window found; avoid clobbering by splitting - vim.command(":vsp") - - # Show a PC marker for each thread - for thread in process: - loc = GetPCSourceLocation(thread) - if not loc: - # no valid source locations for PCs. hide all existing PC - # markers - continue - - buf = None - (tid, fname, line, col) = loc - buffers = self.get_user_buffers(fname) - is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() - if len(buffers) == 1: - buf = buffers[0] - if buf != vim.current.buffer: - # Vim has an open buffer to the required file: select it - vim.command('execute ":%db"' % buf.number) - elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: - # FIXME: If current buffer is modified, vim will complain when we try to switch away. - # Find a way to detect if the current buffer is modified, - # and...warn instead? - vim.command('execute ":e %s"' % fname) - buf = vim.current.buffer - elif len(buffers) > 1 and goto_file: - # FIXME: multiple open buffers match PC location - continue - else: - continue - - self.pcSigns.append(PCSign(buf, line, is_selected)) - - if is_selected and goto_file: - # if the selected file has a PC marker, move the cursor there - # too - curname = vim.current.buffer.name - if curname is not None and is_same_file(curname, fname): - move_cursor(line, 0) - elif move_cursor: - print("FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname)) - - def update_breakpoints(self, target, buffers): - """ Decorates buffer with signs corresponding to breakpoints in target. """ - - def GetBreakpointLocations(bp): - """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ - if not bp.IsValid(): - sys.stderr.write("breakpoint is invalid, no locations") - return [] - - ret = [] - numLocs = bp.GetNumLocations() - for i in range(numLocs): - loc = bp.GetLocationAtIndex(i) - desc = get_description(loc, lldb.eDescriptionLevelFull) - match = re.search('at\ ([^:]+):([\d]+)', desc) - try: - lineNum = int(match.group(2).strip()) - ret.append((loc.IsResolved(), match.group(1), lineNum)) - except ValueError as e: - sys.stderr.write( - "unable to parse breakpoint location line number: '%s'" % - match.group(2)) - sys.stderr.write(str(e)) - - return ret - - if target is None or not target.IsValid(): - return - - needed_bps = {} - for bp_index in range(target.GetNumBreakpoints()): - bp = target.GetBreakpointAtIndex(bp_index) - locations = GetBreakpointLocations(bp) - for (is_resolved, file, line) in GetBreakpointLocations(bp): - for buf in buffers: - if file in buf.name: - needed_bps[(buf, line, is_resolved)] = bp - - # Hide any signs that correspond with disabled breakpoints - del_list = [] - for (b, l, r) in self.breakpointSigns: - if (b, l, r) not in needed_bps: - self.breakpointSigns[(b, l, r)].hide() - del_list.append((b, l, r)) - for d in del_list: - del self.breakpointSigns[d] - - # Show any signs for new breakpoints - for (b, l, r) in needed_bps: - bp = needed_bps[(b, l, r)] - if self.haveBreakpoint(b.name, l): - self.markedBreakpoints[(b.name, l)].append(bp) - else: - self.markedBreakpoints[(b.name, l)] = [bp] - - if (b, l, r) not in self.breakpointSigns: - s = BreakpointSign(b, l, r) - self.breakpointSigns[(b, l, r)] = s - - def update(self, target, status, controller, goto_file=False): - """ Updates debugger info panels and breakpoint/pc marks and prints - status to the vim status line. If goto_file is True, the user's - cursor is moved to the source PC location in the selected frame. - """ - - self.paneCol.update(target, controller) - self.update_breakpoints(target, self.get_user_buffers()) - - if target is not None and target.IsValid(): - process = target.GetProcess() - if process is not None and process.IsValid(): - self.update_pc(process, self.get_user_buffers, goto_file) - - if status is not None and len(status) > 0: - print(status) - - def haveBreakpoint(self, file, line): - """ Returns True if we have a breakpoint at file:line, False otherwise """ - return (file, line) in self.markedBreakpoints - - def getBreakpoints(self, fname, line): - """ Returns the LLDB SBBreakpoint object at fname:line """ - if self.haveBreakpoint(fname, line): - return self.markedBreakpoints[(fname, line)] - else: - return None - - def deleteBreakpoints(self, name, line): - del self.markedBreakpoints[(name, line)] - - def showWindow(self, name): - """ Shows (un-hides) window pane specified by name """ - if not self.paneCol.havePane(name): - sys.stderr.write("unknown window: %s" % name) - return False - self.paneCol.prepare([name]) - return True - - def hideWindow(self, name): - """ Hides window pane specified by name """ - if not self.paneCol.havePane(name): - sys.stderr.write("unknown window: %s" % name) - return False - self.paneCol.hide([name]) - return True - -global ui -ui = UI()