188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea#
388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea# This file defines the layer that talks to lldb
488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea#
588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleaimport os, re, sys
788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleaimport lldb
888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleaimport vim
988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleafrom vim_ui import UI
1088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
1188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea# =================================================
1288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea# Convert some enum value to its string counterpart
1388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea# =================================================
1488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
1588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea# Shamelessly copy/pasted from lldbutil.py in the test suite
1688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleadef state_type_to_str(enum):
1788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  """Returns the stateType string given an enum."""
1888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  if enum == lldb.eStateInvalid:
1988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "invalid"
2088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateUnloaded:
2188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "unloaded"
2288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateConnected:
2388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "connected"
2488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateAttaching:
2588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "attaching"
2688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateLaunching:
2788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "launching"
2888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateStopped:
2988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "stopped"
3088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateRunning:
3188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "running"
3288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateStepping:
3388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "stepping"
3488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateCrashed:
3588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "crashed"
3688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateDetached:
3788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "detached"
3888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateExited:
3988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "exited"
4088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  elif enum == lldb.eStateSuspended:
4188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return "suspended"
4288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  else:
4388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    raise Exception("Unknown StateType enum")
4488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
4588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleaclass StepType:
4688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  INSTRUCTION = 1
4788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  INSTRUCTION_OVER = 2
4888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  INTO = 3
4988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  OVER = 4
5088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  OUT = 5
5188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
5288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleaclass LLDBController(object):
5388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  """ Handles Vim and LLDB events such as commands and lldb events. """
5488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
5588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to
5688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  # servicing LLDB events from the main UI thread. Usually, we only process events that are already
5788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  # sitting on the queue. But in some situations (when we are expecting an event as a result of some
5888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  # user interaction) we want to wait for it. The constants below set these wait period in which the
5988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher
6088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at
6188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  # times.
6288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  eventDelayStep = 2
6388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  eventDelayLaunch = 1
6488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  eventDelayContinue = 1
6588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
6688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def __init__(self):
6788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Creates the LLDB SBDebugger object and initializes the UI class. """
6888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.target = None
6988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.process = None
7088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.load_dependent_modules = True
7188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
7288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.dbg = lldb.SBDebugger.Create()
7388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.commandInterpreter = self.dbg.GetCommandInterpreter()
7488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
7588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.ui = UI()
7688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
7788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def completeCommand(self, a, l, p):
7888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Returns a list of viable completions for command a with length l and cursor at p  """
7988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
8088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    assert l[0] == 'L'
8188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    # Remove first 'L' character that all commands start with
8288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    l = l[1:]
8388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
8488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    # Adjust length as string has 1 less character
8588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    p = int(p) - 1
8688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
8788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    result = lldb.SBStringList()
8888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result)
8988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
9088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if num == -1:
9188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      # FIXME: insert completion character... what's a completion character?
9288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      pass
9388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    elif num == -2:
9488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      # FIXME: replace line with result.GetStringAtIndex(0)
9588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      pass
9688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
9788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if result.GetSize() > 0:
9888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      results =  filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())])
9988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      return results
10088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    else:
10188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      return []
10288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
10388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doStep(self, stepType):
10488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Perform a step command and block the UI for eventDelayStep seconds in order to process
10588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        events on lldb's event queue.
10688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to
10788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea               the main thread to avoid the appearance of a "hang". If this happens, the UI will
10888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea               update whenever; usually when the user moves the cursor. This is somewhat annoying.
10988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """
11088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if not self.process:
11188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      sys.stderr.write("No process to step")
11288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      return
11388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
11488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    t = self.process.GetSelectedThread()
11588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if stepType == StepType.INSTRUCTION:
11688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      t.StepInstruction(False)
11788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if stepType == StepType.INSTRUCTION_OVER:
11888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      t.StepInstruction(True)
11988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    elif stepType == StepType.INTO:
12088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      t.StepInto()
12188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    elif stepType == StepType.OVER:
12288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      t.StepOver()
12388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    elif stepType == StepType.OUT:
12488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      t.StepOut()
12588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
12688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.processPendingEvents(self.eventDelayStep, True)
12788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
12888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doSelect(self, command, args):
12988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Like doCommand, but suppress output when "select" is the first argument."""
13088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    a = args.split(' ')
13188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return self.doCommand(command, args, "select" != a[0], True)
13288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
13388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doProcess(self, args):
13488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead
13588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        of the command interpreter to start the inferior process.
13688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """
13788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    a = args.split(' ')
13888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'):
13988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.doCommand("process", args)
14088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      #self.ui.update(self.target, "", self)
14188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    else:
14288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.doLaunch('-s' not in args, "")
14388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
1443451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea  def doAttach(self, process_name):
1453451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    """ Handle process attach.  """
1463451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    error = lldb.SBError()
1473451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea
1483451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    self.processListener = lldb.SBListener("process_event_listener")
1493451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    self.target = self.dbg.CreateTarget('')
1503451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error)
1513451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    if not error.Success():
1523451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea      sys.stderr.write("Error during attach: " + str(error))
1533451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea      return
1543451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea
1553451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    self.ui.activate()
1563451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    self.pid = self.process.GetProcessID()
1573451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea
1583451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    print "Attached to %s (pid=%d)" % (process_name, self.pid)
1593451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea
1603451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea  def doDetach(self):
1613451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea    if self.process is not None and self.process.IsValid():
1623451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea      pid = self.process.GetProcessID()
1633451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea      state = state_type_to_str(self.process.GetState())
1643451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea      self.process.Detach()
1653451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea      self.processPendingEvents(self.eventDelayLaunch)
1663451b9eed7e9d5bcca72220f4dcdc4c011ef930cDaniel Malea
16788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doLaunch(self, stop_at_entry, args):
16888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Handle process launch.  """
16988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    error = lldb.SBError()
17088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
17188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    fs = self.target.GetExecutable()
17288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    exe = os.path.join(fs.GetDirectory(), fs.GetFilename())
17388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if self.process is not None and self.process.IsValid():
17488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      pid = self.process.GetProcessID()
17588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      state = state_type_to_str(self.process.GetState())
17688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.process.Destroy()
17788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
17888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    launchInfo = lldb.SBLaunchInfo(args.split(' '))
17988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.process = self.target.Launch(launchInfo, error)
18088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if not error.Success():
18188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      sys.stderr.write("Error during launch: " + str(error))
18288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      return
18388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
18488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    # launch succeeded, store pid and add some event listeners
18588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.pid = self.process.GetProcessID()
18688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.processListener = lldb.SBListener("process_event_listener")
18788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged)
18888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
18988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    print "Launched %s %s (pid=%d)" % (exe, args, self.pid)
19088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
19188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if not stop_at_entry:
19288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.doContinue()
19388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    else:
19488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.processPendingEvents(self.eventDelayLaunch)
19588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
19688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doTarget(self, args):
19788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Pass target command to interpreter, except if argument is not one of the valid options, or
19888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        is create, in which case try to create a target with the argument as the executable. For example:
19988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea          target list        ==> handled by interpreter
20088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea          target create blah ==> custom creation of target 'blah'
20188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea          target blah        ==> also creates target blah
20288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """
20388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    target_args = [#"create",
20488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea                   "delete",
20588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea                   "list",
20688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea                   "modules",
20788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea                   "select",
20888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea                   "stop-hook",
20988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea                   "symbols",
21088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea                   "variable"]
21188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
21288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    a = args.split(' ')
21388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if len(args) == 0 or (len(a) > 0 and a[0] in target_args):
21488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.doCommand("target", args)
21588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      return
21688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    elif len(a) > 1 and a[0] == "create":
21788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      exe = a[1]
21888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    elif len(a) == 1 and a[0] not in target_args:
21988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      exe = a[0]
22088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
22188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    err = lldb.SBError()
22288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err)
22388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if not self.target:
22488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err)))
22588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      return
22688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
22788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.ui.activate()
22888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.ui.update(self.target, "created target %s" % str(exe), self)
22988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
23088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doContinue(self):
23188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Handle 'contiue' command.
23288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param.
23388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """
23488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if not self.process or not self.process.IsValid():
23588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      sys.stderr.write("No process to continue")
23688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      return
23788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
23888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.process.Continue()
23988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.processPendingEvents(self.eventDelayContinue)
24088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
24188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doBreakpoint(self, args):
24288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Handle breakpoint command with command interpreter, except if the user calls
24388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        "breakpoint" with no other args, in which case add a breakpoint at the line
24488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        under the cursor.
24588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """
24688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    a = args.split(' ')
24788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if len(args) == 0:
24888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      show_output = False
24988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
25088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      # User called us with no args, so toggle the bp under cursor
25188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      cw = vim.current.window
25288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      cb = vim.current.buffer
25388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      name = cb.name
25488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      line = cw.cursor[0]
25588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
25688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      # Since the UI is responsbile for placing signs at bp locations, we have to
25788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      # ask it if there already is one or more breakpoints at (file, line)...
25888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      if self.ui.haveBreakpoint(name, line):
25988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        bps = self.ui.getBreakpoints(name, line)
26088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        args = "delete %s" % " ".join([str(b.GetID()) for b in bps])
26188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        self.ui.deleteBreakpoints(name, line)
26288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      else:
26388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        args = "set -f %s -l %d" % (name, line)
26488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    else:
26588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      show_output = True
26688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
26788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.doCommand("breakpoint", args, show_output)
26888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return
26988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
27088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doRefresh(self):
27188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ process pending events and update UI on request """
27288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    status = self.processPendingEvents()
27388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
27488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doShow(self, name):
27588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ handle :Lshow <name> """
2765d414624837b0fa6d9ec21fdb23326ad5879f1b1Daniel Malea    if not name:
2775d414624837b0fa6d9ec21fdb23326ad5879f1b1Daniel Malea      self.ui.activate()
2785d414624837b0fa6d9ec21fdb23326ad5879f1b1Daniel Malea      return
2795d414624837b0fa6d9ec21fdb23326ad5879f1b1Daniel Malea
28088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if self.ui.showWindow(name):
28188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.ui.update(self.target, "", self)
28288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
28388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doHide(self, name):
28488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ handle :Lhide <name> """
28588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if self.ui.hideWindow(name):
28688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.ui.update(self.target, "", self)
28788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
28888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doExit(self):
28988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.dbg.Terminate()
29088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.dbg = None
29188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
29288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def getCommandResult(self, command, command_args):
29388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Run cmd in the command interpreter and returns (success, output) """
29488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    result = lldb.SBCommandReturnObject()
29588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    cmd = "%s %s" % (command, command_args)
29688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
29788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.commandInterpreter.HandleCommand(cmd, result)
29888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError())
29988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
30088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def doCommand(self, command, command_args, print_on_success = True, goto_file=False):
30188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Run cmd in interpreter and print result (success or failure) on the vim status line. """
30288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    (success, output) = self.getCommandResult(command, command_args)
30388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if success:
30488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.ui.update(self.target, "", self, goto_file)
30588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      if len(output) > 0 and print_on_success:
30688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        print output
30788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    else:
30888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      sys.stderr.write(output)
30988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
31088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def getCommandOutput(self, command, command_args=""):
31188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ runs cmd in the command interpreter andreturns (status, result) """
31288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    result = lldb.SBCommandReturnObject()
31388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    cmd = "%s %s" % (command, command_args)
31488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    self.commandInterpreter.HandleCommand(cmd, result)
31588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError())
31688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
31788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  def processPendingEvents(self, wait_seconds=0, goto_file=True):
31888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """ Handle any events that are queued from the inferior.
31988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        Blocks for at most wait_seconds, or if wait_seconds == 0,
32088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        process only events that are already queued.
32188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    """
32288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
32388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    status = None
32488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    num_events_handled = 0
32588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
32688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if self.process is not None:
32788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      event = lldb.SBEvent()
32888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      old_state = self.process.GetState()
32988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      new_state = None
33088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      done = False
33188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited:
33288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        # Early-exit if we are in 'boring' states
33388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        pass
33488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      else:
33588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        while not done and self.processListener is not None:
33688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea          if not self.processListener.PeekAtNextEvent(event):
33788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea            if wait_seconds > 0:
33888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea              # No events on the queue, but we are allowed to wait for wait_seconds
33988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea              # for any events to show up.
34088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea              self.processListener.WaitForEvent(wait_seconds, event)
34188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea              new_state = lldb.SBProcess.GetStateFromEvent(event)
34288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
34388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea              num_events_handled += 1
34488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
34588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea            done = not self.processListener.PeekAtNextEvent(event)
34688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea          else:
34788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea            # An event is on the queue, process it here.
34888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea            self.processListener.GetNextEvent(event)
34988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea            new_state = lldb.SBProcess.GetStateFromEvent(event)
35088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
351315f54f3d3fa5a46f02d0553ab2ee385815f8140Daniel Malea            # continue if stopped after attaching
352315f54f3d3fa5a46f02d0553ab2ee385815f8140Daniel Malea            if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped:
353315f54f3d3fa5a46f02d0553ab2ee385815f8140Daniel Malea              self.process.Continue()
354315f54f3d3fa5a46f02d0553ab2ee385815f8140Daniel Malea
35588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea            # If needed, perform any event-specific behaviour here
35688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea            num_events_handled += 1
35788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
35888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    if num_events_handled == 0:
35988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      pass
36088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea    else:
36188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      if old_state == new_state:
36288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea        status = ""
36388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      self.ui.update(self.target, status, self, goto_file)
36488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
36588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
36688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleadef returnCompleteCommand(a, l, p):
36788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  """ Returns a "\n"-separated string with possible completion results
36888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      for command a with length l and cursor at p.
36988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  """
37088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  separator = "\n"
37188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  results = ctrl.completeCommand(a, l, p)
37288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  vim.command('return "%s%s"' % (separator.join(results), separator))
37388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
37488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleadef returnCompleteWindow(a, l, p):
37588cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  """ Returns a "\n"-separated string with possible completion results
37688cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      for commands that expect a window name parameter (like hide/show).
37788cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea      FIXME: connect to ctrl.ui instead of hardcoding the list here
37888cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  """
37988cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  separator = "\n"
38088cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers']
38188cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea  vim.command('return "%s%s"' % (separator.join(results), separator))
38288cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Malea
38388cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleaglobal ctrl
38488cd3fd2f91506c5a9efd660fc0fe92f09b08117Daniel Maleactrl = LLDBController()
385