1##===-- debuggerdriver.py ------------------------------------*- Python -*-===##
2##
3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4# See https://llvm.org/LICENSE.txt for license information.
5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6##
7##===----------------------------------------------------------------------===##
8
9
10import lldb
11import lldbutil
12import sys
13from threading import Thread
14
15
16class DebuggerDriver(Thread):
17    """ Drives the debugger and responds to events. """
18
19    def __init__(self, debugger, event_queue):
20        Thread.__init__(self)
21        self.event_queue = event_queue
22        # This is probably not great because it does not give liblldb a chance
23        # to clean up
24        self.daemon = True
25        self.initialize(debugger)
26
27    def initialize(self, debugger):
28        self.done = False
29        self.debugger = debugger
30        self.listener = debugger.GetListener()
31        if not self.listener.IsValid():
32            raise "Invalid listener"
33
34        self.listener.StartListeningForEventClass(self.debugger,
35                                                  lldb.SBTarget.GetBroadcasterClassName(),
36                                                  lldb.SBTarget.eBroadcastBitBreakpointChanged
37                                                  #| lldb.SBTarget.eBroadcastBitModuleLoaded
38                                                  #| lldb.SBTarget.eBroadcastBitModuleUnloaded
39                                                  | lldb.SBTarget.eBroadcastBitWatchpointChanged
40                                                  #| lldb.SBTarget.eBroadcastBitSymbolLoaded
41                                                  )
42
43        self.listener.StartListeningForEventClass(self.debugger,
44                                                  lldb.SBThread.GetBroadcasterClassName(),
45                                                  lldb.SBThread.eBroadcastBitStackChanged
46                                                  #  lldb.SBThread.eBroadcastBitBreakpointChanged
47                                                  | lldb.SBThread.eBroadcastBitThreadSuspended
48                                                  | lldb.SBThread.eBroadcastBitThreadResumed
49                                                  | lldb.SBThread.eBroadcastBitSelectedFrameChanged
50                                                  | lldb.SBThread.eBroadcastBitThreadSelected
51                                                  )
52
53        self.listener.StartListeningForEventClass(self.debugger,
54                                                  lldb.SBProcess.GetBroadcasterClassName(),
55                                                  lldb.SBProcess.eBroadcastBitStateChanged
56                                                  | lldb.SBProcess.eBroadcastBitInterrupt
57                                                  | lldb.SBProcess.eBroadcastBitSTDOUT
58                                                  | lldb.SBProcess.eBroadcastBitSTDERR
59                                                  | lldb.SBProcess.eBroadcastBitProfileData
60                                                  )
61        self.listener.StartListeningForEventClass(self.debugger,
62                                                  lldb.SBCommandInterpreter.GetBroadcasterClass(),
63                                                  lldb.SBCommandInterpreter.eBroadcastBitThreadShouldExit
64                                                  | lldb.SBCommandInterpreter.eBroadcastBitResetPrompt
65                                                  | lldb.SBCommandInterpreter.eBroadcastBitQuitCommandReceived
66                                                  | lldb.SBCommandInterpreter.eBroadcastBitAsynchronousOutputData
67                                                  | lldb.SBCommandInterpreter.eBroadcastBitAsynchronousErrorData
68                                                  )
69
70    def createTarget(self, target_image, args=None):
71        self.handleCommand("target create %s" % target_image)
72        if args is not None:
73            self.handleCommand("settings set target.run-args %s" % args)
74
75    def attachProcess(self, pid):
76        self.handleCommand("process attach -p %d" % pid)
77        pass
78
79    def loadCore(self, corefile):
80        self.handleCommand("target create -c %s" % corefile)
81        pass
82
83    def setDone(self):
84        self.done = True
85
86    def isDone(self):
87        return self.done
88
89    def getPrompt(self):
90        return self.debugger.GetPrompt()
91
92    def getCommandInterpreter(self):
93        return self.debugger.GetCommandInterpreter()
94
95    def getSourceManager(self):
96        return self.debugger.GetSourceManager()
97
98    def setSize(self, width, height):
99        # FIXME: respect height
100        self.debugger.SetTerminalWidth(width)
101
102    def getTarget(self):
103        return self.debugger.GetTargetAtIndex(0)
104
105    def handleCommand(self, cmd):
106        ret = lldb.SBCommandReturnObject()
107        self.getCommandInterpreter().HandleCommand(cmd, ret)
108        return ret
109
110    def eventLoop(self):
111        while not self.isDone():
112            event = lldb.SBEvent()
113            got_event = self.listener.WaitForEvent(lldb.UINT32_MAX, event)
114            if got_event and not event.IsValid():
115                self.winAddStr("Warning: Invalid or no event...")
116                continue
117            elif not event.GetBroadcaster().IsValid():
118                continue
119
120            self.event_queue.put(event)
121
122    def run(self):
123        self.eventLoop()
124
125    def terminate(self):
126        lldb.SBDebugger.Terminate()
127        sys.exit(0)
128
129
130def createDriver(debugger, event_queue):
131    driver = DebuggerDriver(debugger, event_queue)
132    # driver.start()
133    # if pid specified:
134    # - attach to pid
135    # else if core file specified
136    # - create target from corefile
137    # else
138    # - create target from file
139    # - settings append target.run-args <args-from-cmdline>
140    # source .lldbinit file
141
142    return driver
143