Merge pull request #29 from IngoHeimbach/develop
Added LLDB debugger support
This commit is contained in:
commit
fc1f09cd88
@ -17,6 +17,7 @@ Vebugger is built as a generic framework for building frontends for
|
|||||||
interactive shell debugger, and comes with implementations for:
|
interactive shell debugger, and comes with implementations for:
|
||||||
|
|
||||||
* GDB - doesn't need introdcution...
|
* GDB - doesn't need introdcution...
|
||||||
|
* LLDB - debugger based on LLVM for C-family languages
|
||||||
* JDB - a Java debugger
|
* JDB - a Java debugger
|
||||||
* Mdbg - a .NET debugger(Windows only)
|
* Mdbg - a .NET debugger(Windows only)
|
||||||
* PDB - a Python module for debugging Python scripts
|
* PDB - a Python module for debugging Python scripts
|
||||||
|
139
autoload/vebugger/lldb.vim
Normal file
139
autoload/vebugger/lldb.vim
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
let s:script_dir_path=expand('<sfile>:p:h')
|
||||||
|
|
||||||
|
function! vebugger#lldb#start(binaryFile,args)
|
||||||
|
let l:debuggerExe=vebugger#util#getToolFullPath('python','lldb','python2')
|
||||||
|
let l:debugger=vebugger#std#startDebugger(shellescape(l:debuggerExe)
|
||||||
|
\.' '.s:script_dir_path.'/lldb_wrapper.py '.fnameescape(a:binaryFile))
|
||||||
|
|
||||||
|
let l:debugger.state.lldb={}
|
||||||
|
|
||||||
|
if get(a:args,'pid') "Attach to process
|
||||||
|
call l:debugger.writeLine('process attach --pid '.string(a:args.pid))
|
||||||
|
elseif has_key(a:args,'con') "Attach to lldbserver
|
||||||
|
call l:debugger.writeLine('platform connect connect://'.a:args.con)
|
||||||
|
else
|
||||||
|
call l:debugger.writeLine('settings set target.run-args '.vebugger#util#commandLineArgsForProgram(a:args))
|
||||||
|
if !has('win32')
|
||||||
|
call vebugger#std#openShellBuffer(l:debugger)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" TODO: remove 'and false'; add a temporary breakpoint to lldb
|
||||||
|
if has_key(a:args,'entry') && 0
|
||||||
|
" call l:debugger.writeLine('tbreak '.a:args.entry)
|
||||||
|
" call l:debugger.writeLine('run')
|
||||||
|
else
|
||||||
|
call l:debugger.writeLine('breakpoint set --name main')
|
||||||
|
call l:debugger.writeLine('process launch')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
call l:debugger.addReadHandler(function('vebugger#lldb#_readProgramOutput'))
|
||||||
|
call l:debugger.addReadHandler(function('vebugger#lldb#_readWhere'))
|
||||||
|
call l:debugger.addReadHandler(function('vebugger#lldb#_readFinish'))
|
||||||
|
call l:debugger.addReadHandler(function('vebugger#lldb#_readEvaluatedExpressions'))
|
||||||
|
|
||||||
|
call l:debugger.setWriteHandler('std','flow',function('vebugger#lldb#_writeFlow'))
|
||||||
|
call l:debugger.setWriteHandler('std','breakpoints',function('vebugger#lldb#_writeBreakpoints'))
|
||||||
|
call l:debugger.setWriteHandler('std','closeDebugger',function('vebugger#lldb#_closeDebugger'))
|
||||||
|
call l:debugger.setWriteHandler('std','evaluateExpressions',function('vebugger#lldb#_requestEvaluateExpression'))
|
||||||
|
call l:debugger.setWriteHandler('std','executeStatements',function('vebugger#lldb#_executeStatements'))
|
||||||
|
|
||||||
|
call l:debugger.generateWriteActionsFromTemplate()
|
||||||
|
|
||||||
|
call l:debugger.std_addAllBreakpointActions(g:vebugger_breakpoints)
|
||||||
|
|
||||||
|
return l:debugger
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_readProgramOutput(pipeName,line,readResult,debugger)
|
||||||
|
if 'out'==a:pipeName
|
||||||
|
\&&(a:line=~'\v^program_stdout:'
|
||||||
|
\||a:line=~'\v^program_stderr:')
|
||||||
|
let a:readResult.std.programOutput={'line':strpart(a:line, 16)}
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_readWhere(pipeName,line,readResult,debugger)
|
||||||
|
if 'out'==a:pipeName
|
||||||
|
\&&a:line=~'\v^where:'
|
||||||
|
let l:matches=matchlist(a:line,'\v^where:\s([^:]+):(\d+)')
|
||||||
|
if 2<len(l:matches)
|
||||||
|
let l:file=l:matches[1]
|
||||||
|
let l:file=fnamemodify(l:file,':~:.')
|
||||||
|
let a:readResult.std.location={
|
||||||
|
\'file':(l:file),
|
||||||
|
\'line':str2nr(l:matches[2])}
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_readFinish(pipeName,line,readResult,debugger)
|
||||||
|
if 'out'==a:pipeName
|
||||||
|
\&&a:line=~'\v^program_state:\sExited'
|
||||||
|
let a:readResult.std.programFinish={'finish':1}
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_writeFlow(writeAction,debugger)
|
||||||
|
if 'stepin'==a:writeAction
|
||||||
|
call a:debugger.writeLine('step')
|
||||||
|
elseif 'stepover'==a:writeAction
|
||||||
|
call a:debugger.writeLine('next')
|
||||||
|
elseif 'stepout'==a:writeAction
|
||||||
|
call a:debugger.writeLine('finish')
|
||||||
|
elseif 'continue'==a:writeAction
|
||||||
|
call a:debugger.writeLine('continue')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_closeDebugger(writeAction,debugger)
|
||||||
|
call a:debugger.writeLine('quit')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_writeBreakpoints(writeAction,debugger)
|
||||||
|
for l:breakpoint in a:writeAction
|
||||||
|
if 'add'==(l:breakpoint.action)
|
||||||
|
call a:debugger.writeLine('br '.fnameescape(l:breakpoint.file).':'.l:breakpoint.line)
|
||||||
|
elseif 'remove'==l:breakpoint.action
|
||||||
|
call a:debugger.writeLine('clear '.fnameescape(l:breakpoint.file).':'.l:breakpoint.line)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_requestEvaluateExpression(writeAction,debugger)
|
||||||
|
for l:evalAction in a:writeAction
|
||||||
|
call a:debugger.writeLine('print '.l:evalAction.expression)
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_executeStatements(writeAction,debugger)
|
||||||
|
for l:evalAction in a:writeAction
|
||||||
|
if has_key(l:evalAction,'statement')
|
||||||
|
"Use eval to run the statement - but first we need to remove the ;
|
||||||
|
call a:debugger.writeLine('print '.substitute(l:evalAction.statement,'\v;\s*$','',''))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vebugger#lldb#_readEvaluatedExpressions(pipeName,line,readResult,debugger) dict
|
||||||
|
if 'out' == a:pipeName
|
||||||
|
if has_key(self, 'nextExpressionToBePrinted')
|
||||||
|
\&&a:line=~'\v^debugger_output:'
|
||||||
|
let l:matches=matchlist(a:line,'\v^[^\$]*\$(\d+) \= (.*)$')
|
||||||
|
if 2<len(l:matches)
|
||||||
|
let l:expression=l:matches[1]
|
||||||
|
let l:value=l:matches[2]
|
||||||
|
let a:readResult.std.evaluatedExpression={
|
||||||
|
\'expression':self.nextExpressionToBePrinted,
|
||||||
|
\'value':(l:value)}
|
||||||
|
endif
|
||||||
|
call remove(self,'nextExpressionToBePrinted')
|
||||||
|
else
|
||||||
|
let l:matches=matchlist(a:line,'\v^print (.+)$')
|
||||||
|
if 1<len(l:matches)
|
||||||
|
let self.nextExpressionToBePrinted=l:matches[1]
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
253
autoload/vebugger/lldb_wrapper.py
Executable file
253
autoload/vebugger/lldb_wrapper.py
Executable file
@ -0,0 +1,253 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
FilePosition = collections.namedtuple('FilePosition', ['filepath', 'linenumber'])
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Just try for LLDB in case PYTHONPATH is already correctly setup
|
||||||
|
import lldb
|
||||||
|
except ImportError:
|
||||||
|
lldb_python_dirs = []
|
||||||
|
# lldb is not in the PYTHONPATH, try some defaults for the current platform
|
||||||
|
platform_system = platform.system()
|
||||||
|
if platform_system == 'Darwin':
|
||||||
|
# On Darwin, try the currently selected Xcode directory
|
||||||
|
try:
|
||||||
|
xcode_dir = subprocess.check_output(['xcode-select', '--print-path'])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
xcode_dir = None
|
||||||
|
if xcode_dir:
|
||||||
|
lldb_python_dirs.append(
|
||||||
|
os.path.realpath(
|
||||||
|
os.path.join(xcode_dir, '../SharedFrameworks/LLDB.framework/Versions/A/Resources/Python')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lldb_python_dirs.append(
|
||||||
|
'/Library/Developer/CommandLineTools/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python'
|
||||||
|
)
|
||||||
|
for lldb_python_dir in lldb_python_dirs:
|
||||||
|
if os.path.exists(lldb_python_dir):
|
||||||
|
if lldb_python_dir not in sys.path:
|
||||||
|
sys.path.append(lldb_python_dir)
|
||||||
|
try:
|
||||||
|
import lldb
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
sys.stderr.write('Error: could not locate the "lldb" module, please set PYTHONPATH correctly\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
class NoCustomCommandError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Debugger(object):
|
||||||
|
class BreakpointManager(object):
|
||||||
|
def __init__(self):
|
||||||
|
self._next_breakpoint_id = 1
|
||||||
|
self._location_to_id = {}
|
||||||
|
|
||||||
|
def add_breakpoint(self, filename, linenumber):
|
||||||
|
location = (filename, linenumber)
|
||||||
|
breakpoint_id = self._next_breakpoint_id
|
||||||
|
self._location_to_id[location] = breakpoint_id
|
||||||
|
self._next_breakpoint_id += 1
|
||||||
|
return breakpoint_id
|
||||||
|
|
||||||
|
def remove_breakpoint(self, filename, linenumber):
|
||||||
|
location = (filename, linenumber)
|
||||||
|
breakpoint_id = self._location_to_id[location]
|
||||||
|
del self._location_to_id[location]
|
||||||
|
return breakpoint_id
|
||||||
|
|
||||||
|
def __init__(self, executable):
|
||||||
|
self._executable = executable
|
||||||
|
self._debugger = lldb.SBDebugger.Create()
|
||||||
|
self._debugger.SetAsync(False)
|
||||||
|
self._command_interpreter = self._debugger.GetCommandInterpreter()
|
||||||
|
error = lldb.SBError()
|
||||||
|
self._target = self._debugger.CreateTarget(
|
||||||
|
self._executable, None, None, True, error
|
||||||
|
)
|
||||||
|
self._process = None
|
||||||
|
self._last_debugger_return_obj = None
|
||||||
|
self._state_dict = None
|
||||||
|
self._breakpoint_manager = self.BreakpointManager()
|
||||||
|
self._custom_commands = ['br', 'clear']
|
||||||
|
self._set_options()
|
||||||
|
|
||||||
|
def _set_options(self):
|
||||||
|
# -> first read lldbinit
|
||||||
|
try:
|
||||||
|
with open(os.path.expanduser('~/.lldbinit')) as f:
|
||||||
|
for line in f:
|
||||||
|
self.run_command(line)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
self.run_command('settings set frame-format frame #${frame.index}: ${frame.pc}{ ${module.file.basename}`${function.name}{${function.pc-offset}}}{ at:${line.file.fullpath}:${line.number}}\n')
|
||||||
|
self.run_command('settings set auto-confirm 1')
|
||||||
|
|
||||||
|
def run_command(self, commandline):
|
||||||
|
if self._is_custom_command(commandline):
|
||||||
|
self._run_custom_command(commandline)
|
||||||
|
else:
|
||||||
|
if isinstance(commandline, unicode):
|
||||||
|
commandline = commandline.encode('utf-8')
|
||||||
|
return_obj = lldb.SBCommandReturnObject()
|
||||||
|
self._command_interpreter.HandleCommand(commandline, return_obj)
|
||||||
|
if self._process is None or self._process.GetState() == lldb.eStateInvalid:
|
||||||
|
self._process = self._command_interpreter.GetProcess()
|
||||||
|
self._last_debugger_return_obj = return_obj
|
||||||
|
|
||||||
|
def _is_custom_command(self, commandline):
|
||||||
|
command = commandline.split()[0]
|
||||||
|
return command in self._custom_commands
|
||||||
|
|
||||||
|
def _run_custom_command(self, commandline):
|
||||||
|
def br(arguments):
|
||||||
|
filename, linenumber = arguments[0].split(':')
|
||||||
|
linenumber = int(linenumber)
|
||||||
|
self._breakpoint_manager.add_breakpoint(filename, linenumber)
|
||||||
|
self.run_command('b {}'.format(*arguments))
|
||||||
|
|
||||||
|
def clear(arguments):
|
||||||
|
filename, linenumber = arguments[0].split(':')
|
||||||
|
linenumber = int(linenumber)
|
||||||
|
breakpoint_id = self._breakpoint_manager.remove_breakpoint(filename,
|
||||||
|
linenumber)
|
||||||
|
self.run_command('breakpoint delete {:d}'.format(breakpoint_id))
|
||||||
|
|
||||||
|
if not self._is_custom_command(commandline):
|
||||||
|
raise NoCustomCommandError
|
||||||
|
parts = commandline.split()
|
||||||
|
print('parts:', parts)
|
||||||
|
command = parts[0]
|
||||||
|
arguments = parts[1:]
|
||||||
|
locals()[command](arguments)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def debugger_output(self):
|
||||||
|
if self._last_debugger_return_obj is not None:
|
||||||
|
return_obj = self._last_debugger_return_obj
|
||||||
|
self._last_debugger_return_obj = None
|
||||||
|
return return_obj.GetOutput()
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def where(self):
|
||||||
|
def extract_where(backtrace):
|
||||||
|
where = None
|
||||||
|
pattern = re.compile('at:([^:]+):(\d+)')
|
||||||
|
backtrace_lines = backtrace.split('\n')
|
||||||
|
for line in backtrace_lines:
|
||||||
|
match_obj = pattern.search(line)
|
||||||
|
if match_obj:
|
||||||
|
filepath = match_obj.group(1)
|
||||||
|
linenumber = int(match_obj.group(2))
|
||||||
|
if os.access(filepath, os.R_OK):
|
||||||
|
where = FilePosition(filepath, linenumber)
|
||||||
|
break
|
||||||
|
return where
|
||||||
|
|
||||||
|
where = None
|
||||||
|
self.run_command('bt')
|
||||||
|
debugger_output = self.debugger_output
|
||||||
|
if debugger_output is not None:
|
||||||
|
where = extract_where(debugger_output)
|
||||||
|
return where
|
||||||
|
|
||||||
|
@property
|
||||||
|
def program_stdout(self):
|
||||||
|
stdout = []
|
||||||
|
has_text = True
|
||||||
|
while has_text:
|
||||||
|
text = self._process.GetSTDOUT(1024)
|
||||||
|
if text:
|
||||||
|
stdout.append(text)
|
||||||
|
else:
|
||||||
|
has_text = False
|
||||||
|
return ''.join(stdout)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def program_stderr(self):
|
||||||
|
stderr = []
|
||||||
|
has_text = True
|
||||||
|
while has_text:
|
||||||
|
text = self._process.GetSTDERR(1024)
|
||||||
|
if text:
|
||||||
|
stderr.append(text)
|
||||||
|
else:
|
||||||
|
has_text = False
|
||||||
|
return ''.join(stderr)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def program_state(self):
|
||||||
|
return self._state_id_to_name(self._process.GetState())
|
||||||
|
|
||||||
|
def _state_id_to_name(self, state_id):
|
||||||
|
if self._state_dict is None:
|
||||||
|
self._state_dict = {}
|
||||||
|
for key, value in lldb.__dict__.iteritems():
|
||||||
|
if key.startswith('eState'):
|
||||||
|
self._state_dict[value] = key[6:]
|
||||||
|
return self._state_dict[state_id]
|
||||||
|
|
||||||
|
|
||||||
|
def prefix_output(output, prefix):
|
||||||
|
lines = output.split('\n')
|
||||||
|
lines = [prefix + line for line in lines]
|
||||||
|
prefixed_output = '\n'.join(lines)
|
||||||
|
return prefixed_output
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
sys.stderr.write('An executable is needed as an argument.\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
executable = sys.argv[1]
|
||||||
|
debugger = Debugger(executable)
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = raw_input()
|
||||||
|
# TODO: find a way to check directly if the debugger was terminated
|
||||||
|
if line in ['exit', 'quit']:
|
||||||
|
raise EOFError
|
||||||
|
debugger.run_command(line)
|
||||||
|
program_stdout = debugger.program_stdout
|
||||||
|
if program_stdout:
|
||||||
|
print(prefix_output(program_stdout, 'program_stdout: '))
|
||||||
|
program_stderr = debugger.program_stderr
|
||||||
|
if program_stderr:
|
||||||
|
print(prefix_output(program_stderr, 'program_stderr: '))
|
||||||
|
print(prefix_output(debugger.debugger_output, 'debugger_output: '))
|
||||||
|
where = debugger.where
|
||||||
|
if where:
|
||||||
|
print(prefix_output('{:s}:{:d}'.format(where.filepath, where.linenumber), 'where: '))
|
||||||
|
print(prefix_output(debugger.program_state, 'program_state: '))
|
||||||
|
except EOFError:
|
||||||
|
print('Exiting')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -20,6 +20,7 @@ supports:
|
|||||||
Vebugger is built as a generic framework for building frontends for
|
Vebugger is built as a generic framework for building frontends for
|
||||||
interactive shell debugger, and comes with implementations for:
|
interactive shell debugger, and comes with implementations for:
|
||||||
* GDB - doesn't need introdcution...
|
* GDB - doesn't need introdcution...
|
||||||
|
* LLDB - debugger based on LLVM for C-family languages
|
||||||
* JDB - a Java debugger
|
* JDB - a Java debugger
|
||||||
* Mdbg - a .NET debugger(Windows only)
|
* Mdbg - a .NET debugger(Windows only)
|
||||||
* PDB - a Python module for debugging Python scripts
|
* PDB - a Python module for debugging Python scripts
|
||||||
@ -76,24 +77,32 @@ Example: >
|
|||||||
If a debugger is not in the PATH you can set the direct path to it by setting
|
If a debugger is not in the PATH you can set the direct path to it by setting
|
||||||
g:vebugger_path_XXX, where XXX is the executable used for the debugger:
|
g:vebugger_path_XXX, where XXX is the executable used for the debugger:
|
||||||
|
|
||||||
*g:vebugger_path_gdb* defaults to "gdb"
|
*g:vebugger_path_gdb* defaults to "gdb"
|
||||||
*g:vebugger_path_jdb* defaults to "jdb"
|
*g:vebugger_path_python_lldb* defaults to "python2"
|
||||||
*g:vebugger_path_mdbg* defaults to "Mdbg.exe"
|
*g:vebugger_path_jdb* defaults to "jdb"
|
||||||
*g:vebugger_path_python* defaults to "python"
|
*g:vebugger_path_mdbg* defaults to "Mdbg.exe"
|
||||||
*g:vebugger_path_ruby* defaults to "ruby"
|
*g:vebugger_path_python* defaults to "python"
|
||||||
|
*g:vebugger_path_ruby* defaults to "ruby"
|
||||||
|
|
||||||
Notice that for PDB and RDebug you use "python" and "ruby", since the debugger
|
Notice that for LLDB, PDB and RDebug you use "python_lldb", "python" and
|
||||||
is actually a module bundled in the interpreter.
|
"ruby", since the debugger is actually a module bundled in the interpreter
|
||||||
|
(LLDB is called by a python wrapper because the LLDB executable has no
|
||||||
|
machine interface like GDB to interact with).
|
||||||
|
|
||||||
You can set multiple versions for each debugger, by appending the version name
|
You can set multiple versions for each debugger (except LLDB), by appending
|
||||||
to the debugger name with "_". These versions will be used when the "version"
|
the version name to the debugger name with "_". These versions will be used
|
||||||
argument is supplied when running the debugger:
|
when the "version" argument is supplied when running the debugger:
|
||||||
|
|
||||||
*g:vebugger_path_python_2* defaults to "python2"
|
*g:vebugger_path_python_2* defaults to "python2"
|
||||||
*g:vebugger_path_python_3* defaults to "python3"
|
*g:vebugger_path_python_3* defaults to "python3"
|
||||||
*g:vebugger_path_mdbg_32* No default - use it for the 32bit version of Mdbg
|
*g:vebugger_path_mdbg_32* No default - use it for the 32bit version of Mdbg
|
||||||
*g:vebugger_path_mdbg_64* No default - use it for the 64bit version of Mdbg
|
*g:vebugger_path_mdbg_64* No default - use it for the 64bit version of Mdbg
|
||||||
|
|
||||||
|
For LLDB a special python variable is needed ("g:vebugger_path_python_lldb")
|
||||||
|
since the lldb python api is only python 2 compatible. So, it is possible to
|
||||||
|
use a python 2 interpreter for LLDB and another python version for PDB at
|
||||||
|
the same time.
|
||||||
|
|
||||||
When stepping into functions in unopened files, they are opened with :new by
|
When stepping into functions in unopened files, they are opened with :new by
|
||||||
default. This can be configured by setting *g:vebugger_view_source_cmd*
|
default. This can be configured by setting *g:vebugger_view_source_cmd*
|
||||||
|
|
||||||
@ -153,6 +162,33 @@ attach to or the URL for a GDB-server to connect to.
|
|||||||
The *VBGstartGDBForD* command is the same as VBGstartGDB but for Dlang
|
The *VBGstartGDBForD* command is the same as VBGstartGDB but for Dlang
|
||||||
programs.
|
programs.
|
||||||
|
|
||||||
|
|
||||||
|
LAUNCHING LLDB *vebugger-lldb*
|
||||||
|
|
||||||
|
LLDB can be launched with *vebugger#lldb#start*
|
||||||
|
>
|
||||||
|
call vebugger#lldb#start('a.out',{'args':['hello','world']})
|
||||||
|
<
|
||||||
|
|
||||||
|
The supported extra arguments are:
|
||||||
|
* "args": Command line arguments for the debugged program
|
||||||
|
* "pid": Process id to attach to
|
||||||
|
You can't specify both "args" and "pid".
|
||||||
|
|
||||||
|
LLDB can also be launched with the *VBGstartLLDB* command:
|
||||||
|
>
|
||||||
|
VBGstartLLDB a.out hello world
|
||||||
|
<
|
||||||
|
The *VBGattachLLDB* command searches for processes launched from the EXE to
|
||||||
|
attach to, and attaches to them:
|
||||||
|
>
|
||||||
|
VBGattachLLDB a.out
|
||||||
|
<
|
||||||
|
|
||||||
|
VBGattachLLDB accepts as a second argument the process ID of the process to
|
||||||
|
attach to.
|
||||||
|
|
||||||
|
|
||||||
LAUNCHING JDB *vebugger-jdb*
|
LAUNCHING JDB *vebugger-jdb*
|
||||||
|
|
||||||
JDB is launched with *vebugger#jdb#start*
|
JDB is launched with *vebugger#jdb#start*
|
||||||
|
@ -41,6 +41,24 @@ function! s:attachGDB(...)
|
|||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
command! -nargs=+ -complete=file VBGattachGDB call s:attachGDB(<f-args>)
|
command! -nargs=+ -complete=file VBGattachGDB call s:attachGDB(<f-args>)
|
||||||
|
command! -nargs=+ -complete=file VBGstartLLDB call vebugger#lldb#start([<f-args>][0],{'args':[<f-args>][1:]})
|
||||||
|
function! s:attachLLDB(...)
|
||||||
|
if 1 == a:0
|
||||||
|
let l:processId=vebugger#util#selectProcessOfFile(a:1)
|
||||||
|
if 0 < l:processId
|
||||||
|
call vebugger#lldb#start(a:1, {'pid': l:processId})
|
||||||
|
endif
|
||||||
|
elseif 2 == a:0
|
||||||
|
if a:2 =~ '\v^\d+$'
|
||||||
|
call vebugger#lldb#start(a:1,{'pid': str2nr(a:2)})
|
||||||
|
else
|
||||||
|
call vebugger#lldb#start(a:1, {'con': a:2})
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
throw "Can't call VBGattachLLDB with ".a:0." arguments"
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
command! -nargs=+ -complete=file VBGattachLLDB call s:attachLLDB(<f-args>)
|
||||||
command! -nargs=+ -complete=file VBGstartRDebug call vebugger#rdebug#start([<f-args>][0],{'args':[<f-args>][1:]})
|
command! -nargs=+ -complete=file VBGstartRDebug call vebugger#rdebug#start([<f-args>][0],{'args':[<f-args>][1:]})
|
||||||
command! -nargs=+ -complete=file VBGstartPDB call vebugger#pdb#start([<f-args>][0],{'args':[<f-args>][1:]})
|
command! -nargs=+ -complete=file VBGstartPDB call vebugger#pdb#start([<f-args>][0],{'args':[<f-args>][1:]})
|
||||||
command! -nargs=+ -complete=file VBGstartPDB2 call vebugger#pdb#start([<f-args>][0],{'args':[<f-args>][1:],'version':'2'})
|
command! -nargs=+ -complete=file VBGstartPDB2 call vebugger#pdb#start([<f-args>][0],{'args':[<f-args>][1:],'version':'2'})
|
||||||
|
Loading…
Reference in New Issue
Block a user