##===-- debuggerdriver.py ------------------------------------*- Python -*-===##
##
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
##
##===----------------------------------------------------------------------===##
import lldb
import lldbutil
import sys
from threading import Thread
class DebuggerDriver(Thread):
"""Drives the debugger and responds to events."""
def __init__(self, debugger, event_queue):
Thread.__init__(self)
self.event_queue = event_queue
# This is probably not great because it does not give liblldb a chance
# to clean up
self.daemon = True
self.initialize(debugger)
def initialize(self, debugger):
self.done = False
self.debugger = debugger
self.listener = debugger.GetListener()
if not self.listener.IsValid():
raise "Invalid listener"
self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBTarget.GetBroadcasterClassName(),
lldb.SBTarget.eBroadcastBitBreakpointChanged
# | lldb.SBTarget.eBroadcastBitModuleLoaded
# | lldb.SBTarget.eBroadcastBitModuleUnloaded
| lldb.SBTarget.eBroadcastBitWatchpointChanged
# | lldb.SBTarget.eBroadcastBitSymbolLoaded
)
self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBThread.GetBroadcasterClassName(),
lldb.SBThread.eBroadcastBitStackChanged
# lldb.SBThread.eBroadcastBitBreakpointChanged
| lldb.SBThread.eBroadcastBitThreadSuspended
| lldb.SBThread.eBroadcastBitThreadResumed
| lldb.SBThread.eBroadcastBitSelectedFrameChanged
| lldb.SBThread.eBroadcastBitThreadSelected,
)
self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBProcess.GetBroadcasterClassName(),
lldb.SBProcess.eBroadcastBitStateChanged
| lldb.SBProcess.eBroadcastBitInterrupt
| lldb.SBProcess.eBroadcastBitSTDOUT
| lldb.SBProcess.eBroadcastBitSTDERR
| lldb.SBProcess.eBroadcastBitProfileData,
)
self.listener.StartListeningForEventClass(
self.debugger,
lldb.SBCommandInterpreter.GetBroadcasterClass(),
lldb.SBCommandInterpreter.eBroadcastBitThreadShouldExit
| lldb.SBCommandInterpreter.eBroadcastBitResetPrompt
| lldb.SBCommandInterpreter.eBroadcastBitQuitCommandReceived
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousOutputData
| lldb.SBCommandInterpreter.eBroadcastBitAsynchronousErrorData,
)
def createTarget(self, target_image, args=None):
self.handleCommand("target create %s" % target_image)
if args is not None:
self.handleCommand("settings set target.run-args %s" % args)
def attachProcess(self, pid):
self.handleCommand("process attach -p %d" % pid)
pass
def loadCore(self, corefile):
self.handleCommand("target create -c %s" % corefile)
pass
def setDone(self):
self.done = True
def isDone(self):
return self.done
def getPrompt(self):
return self.debugger.GetPrompt()
def getCommandInterpreter(self):
return self.debugger.GetCommandInterpreter()
def getSourceManager(self):
return self.debugger.GetSourceManager()
def setSize(self, width, height):
# FIXME: respect height
self.debugger.SetTerminalWidth(width)
def getTarget(self):
return self.debugger.GetTargetAtIndex(0)
def handleCommand(self, cmd):
ret = lldb.SBCommandReturnObject()
self.getCommandInterpreter().HandleCommand(cmd, ret)
return ret
def eventLoop(self):
while not self.isDone():
event = lldb.SBEvent()
got_event = self.listener.WaitForEvent(lldb.UINT32_MAX, event)
if got_event and not event.IsValid():
self.winAddStr("Warning: Invalid or no event...")
continue
elif not event.GetBroadcaster().IsValid():
continue
self.event_queue.put(event)
def run(self):
self.eventLoop()
def terminate(self):
lldb.SBDebugger.Terminate()
sys.exit(0)
def createDriver(debugger, event_queue):
driver = DebuggerDriver(debugger, event_queue)
# driver.start()
# if pid specified:
# - attach to pid
# else if core file specified
# - create target from corefile
# else
# - create target from file
# - settings append target.run-args <args-from-cmdline>
# source .lldbinit file
return driver