diff options
| author | Jonas Devlieghere <jonas@devlieghere.com> | 2019-07-23 17:23:36 +0000 |
|---|---|---|
| committer | Jonas Devlieghere <jonas@devlieghere.com> | 2019-07-23 17:23:36 +0000 |
| commit | 6491076ec6800f54a8b1d09a95566b36db00f99d (patch) | |
| tree | faee8f559629a7acaf38aac7d03522cfe49b7d3e /lldb/utils/lui | |
| parent | 6f13637a3e130980456f37647f7628aa7fa7a2b6 (diff) | |
| download | bcm5719-llvm-6491076ec6800f54a8b1d09a95566b36db00f99d.tar.gz bcm5719-llvm-6491076ec6800f54a8b1d09a95566b36db00f99d.zip | |
[Utils] Remove legacy scripts
As pointed out by Nathan in D65155, these scrips don't seem to serve any
real need anymore.
llvm-svn: 366827
Diffstat (limited to 'lldb/utils/lui')
| -rw-r--r-- | lldb/utils/lui/Readme | 36 | ||||
| -rw-r--r-- | lldb/utils/lui/breakwin.py | 93 | ||||
| -rw-r--r-- | lldb/utils/lui/commandwin.py | 130 | ||||
| -rwxr-xr-x | lldb/utils/lui/cui.py | 338 | ||||
| -rw-r--r-- | lldb/utils/lui/debuggerdriver.py | 142 | ||||
| -rw-r--r-- | lldb/utils/lui/eventwin.py | 26 | ||||
| -rw-r--r-- | lldb/utils/lui/lldbutil.py | 1040 | ||||
| -rwxr-xr-x | lldb/utils/lui/lui.py | 152 | ||||
| -rwxr-xr-x | lldb/utils/lui/sandbox.py | 77 | ||||
| -rw-r--r-- | lldb/utils/lui/sourcewin.py | 238 | ||||
| -rw-r--r-- | lldb/utils/lui/statuswin.py | 41 |
11 files changed, 0 insertions, 2313 deletions
diff --git a/lldb/utils/lui/Readme b/lldb/utils/lui/Readme deleted file mode 100644 index 7ba51ce8110..00000000000 --- a/lldb/utils/lui/Readme +++ /dev/null @@ -1,36 +0,0 @@ - -LLDB (Terminal) User Interface ------------------------------- - -This directory contains the curses user interface for LLDB. To use it, ensure Python can find your lldb module. You may have to modify PYTHONPATH for that purpose: - -$ export PYTHONPATH=/path/to/lldb/module - -Then, run the lui.py. To load a core file: -$ ./lui.py --core core - -To create a target from an executable: -$ ./lui.py /bin/echo "hello world" - -To attach to a running process: -$ ./lui.py --attach <pid> - - -Known Issues ------------- -1. Resizing the terminal will most likely cause lui to crash. -2. Missing paging in command-window -3. Only minimal testing (on Ubuntu Linux x86_64) - -Missing Features ----------------- -- stdin/stdout/stderr windows -- memory window -- backtrace window -- threads window -- tab-completion -- syntax-highlighting (via pygments library) -- (local) variables window -- registers window -- disassembly window -- custom layout diff --git a/lldb/utils/lui/breakwin.py b/lldb/utils/lui/breakwin.py deleted file mode 100644 index a12b3a96fe4..00000000000 --- a/lldb/utils/lui/breakwin.py +++ /dev/null @@ -1,93 +0,0 @@ -##===-- breakwin.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 cui -import curses -import lldb -import lldbutil -import re - - -class BreakWin(cui.ListWin): - - def __init__(self, driver, x, y, w, h): - super(BreakWin, self).__init__(x, y, w, h) - self.driver = driver - self.update() - self.showDetails = {} - - def handleEvent(self, event): - if isinstance(event, lldb.SBEvent): - if lldb.SBBreakpoint.EventIsBreakpointEvent(event): - self.update() - if isinstance(event, int): - if event == ord('d'): - self.deleteSelected() - if event == curses.ascii.NL or event == curses.ascii.SP: - self.toggleSelected() - elif event == curses.ascii.TAB: - if self.getSelected() != -1: - target = self.driver.getTarget() - if not target.IsValid(): - return - i = target.GetBreakpointAtIndex(self.getSelected()).id - self.showDetails[i] = not self.showDetails[i] - self.update() - super(BreakWin, self).handleEvent(event) - - def toggleSelected(self): - if self.getSelected() == -1: - return - target = self.driver.getTarget() - if not target.IsValid(): - return - bp = target.GetBreakpointAtIndex(self.getSelected()) - bp.SetEnabled(not bp.IsEnabled()) - - def deleteSelected(self): - if self.getSelected() == -1: - return - target = self.driver.getTarget() - if not target.IsValid(): - return - bp = target.GetBreakpointAtIndex(self.getSelected()) - target.BreakpointDelete(bp.id) - - def update(self): - target = self.driver.getTarget() - if not target.IsValid(): - self.win.erase() - self.win.noutrefresh() - return - selected = self.getSelected() - self.clearItems() - for i in range(0, target.GetNumBreakpoints()): - bp = target.GetBreakpointAtIndex(i) - if bp.IsInternal(): - continue - text = lldbutil.get_description(bp) - # FIXME: Use an API for this, not parsing the description. - match = re.search('SBBreakpoint: id = ([^,]+), (.*)', text) - try: - id = match.group(1) - desc = match.group(2).strip() - if bp.IsEnabled(): - text = '%s: %s' % (id, desc) - else: - text = '%s: (disabled) %s' % (id, desc) - except ValueError as e: - # bp unparsable - pass - - if self.showDetails.setdefault(bp.id, False): - for location in bp: - desc = lldbutil.get_description( - location, lldb.eDescriptionLevelFull) - text += '\n ' + desc - self.addItem(text) - self.setSelected(selected) diff --git a/lldb/utils/lui/commandwin.py b/lldb/utils/lui/commandwin.py deleted file mode 100644 index 7b2fdc1c09e..00000000000 --- a/lldb/utils/lui/commandwin.py +++ /dev/null @@ -1,130 +0,0 @@ -##===-- commandwin.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 cui -import curses -import lldb -from itertools import islice - - -class History(object): - - def __init__(self): - self.data = {} - self.pos = 0 - self.tempEntry = '' - - def previous(self, curr): - if self.pos == len(self.data): - self.tempEntry = curr - - if self.pos < 0: - return '' - if self.pos == 0: - self.pos -= 1 - return '' - if self.pos > 0: - self.pos -= 1 - return self.data[self.pos] - - def next(self): - if self.pos < len(self.data): - self.pos += 1 - - if self.pos < len(self.data): - return self.data[self.pos] - elif self.tempEntry != '': - return self.tempEntry - else: - return '' - - def add(self, c): - self.tempEntry = '' - self.pos = len(self.data) - if self.pos == 0 or self.data[self.pos - 1] != c: - self.data[self.pos] = c - self.pos += 1 - - -class CommandWin(cui.TitledWin): - - def __init__(self, driver, x, y, w, h): - super(CommandWin, self).__init__(x, y, w, h, "Commands") - self.command = "" - self.data = "" - driver.setSize(w, h) - - self.win.scrollok(1) - - self.driver = driver - self.history = History() - - def enterCallback(content): - self.handleCommand(content) - - def tabCompleteCallback(content): - self.data = content - matches = lldb.SBStringList() - commandinterpreter = self.getCommandInterpreter() - commandinterpreter.HandleCompletion( - self.data, self.el.index, 0, -1, matches) - if matches.GetSize() == 2: - self.el.content += matches.GetStringAtIndex(0) - self.el.index = len(self.el.content) - self.el.draw() - else: - self.win.move(self.el.starty, self.el.startx) - self.win.scroll(1) - self.win.addstr("Available Completions:") - self.win.scroll(1) - for m in islice(matches, 1, None): - self.win.addstr(self.win.getyx()[0], 0, m) - self.win.scroll(1) - self.el.draw() - - self.startline = self.win.getmaxyx()[0] - 2 - - self.el = cui.CursesEditLine( - self.win, - self.history, - enterCallback, - tabCompleteCallback) - self.el.prompt = self.driver.getPrompt() - self.el.showPrompt(self.startline, 0) - - def handleCommand(self, cmd): - # enter! - self.win.scroll(1) # TODO: scroll more for longer commands - if cmd == '': - cmd = self.history.previous('') - elif cmd in ('q', 'quit'): - self.driver.terminate() - return - - self.history.add(cmd) - ret = self.driver.handleCommand(cmd) - if ret.Succeeded(): - out = ret.GetOutput() - attr = curses.A_NORMAL - else: - out = ret.GetError() - attr = curses.color_pair(3) # red on black - self.win.addstr(self.startline, 0, out + '\n', attr) - self.win.scroll(1) - self.el.showPrompt(self.startline, 0) - - def handleEvent(self, event): - if isinstance(event, int): - if event == curses.ascii.EOT and self.el.content == '': - # When the command is empty, treat CTRL-D as EOF. - self.driver.terminate() - return - self.el.handleEvent(event) - - def getCommandInterpreter(self): - return self.driver.getCommandInterpreter() diff --git a/lldb/utils/lui/cui.py b/lldb/utils/lui/cui.py deleted file mode 100755 index fffb812fbb9..00000000000 --- a/lldb/utils/lui/cui.py +++ /dev/null @@ -1,338 +0,0 @@ -##===-- cui.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 curses -import curses.ascii -import threading - - -class CursesWin(object): - - def __init__(self, x, y, w, h): - self.win = curses.newwin(h, w, y, x) - self.focus = False - - def setFocus(self, focus): - self.focus = focus - - def getFocus(self): - return self.focus - - def canFocus(self): - return True - - def handleEvent(self, event): - return - - def draw(self): - return - - -class TextWin(CursesWin): - - def __init__(self, x, y, w): - super(TextWin, self).__init__(x, y, w, 1) - self.win.bkgd(curses.color_pair(1)) - self.text = '' - self.reverse = False - - def canFocus(self): - return False - - def draw(self): - w = self.win.getmaxyx()[1] - text = self.text - if len(text) > w: - #trunc_length = len(text) - w - text = text[-w + 1:] - if self.reverse: - self.win.addstr(0, 0, text, curses.A_REVERSE) - else: - self.win.addstr(0, 0, text) - self.win.noutrefresh() - - def setReverse(self, reverse): - self.reverse = reverse - - def setText(self, text): - self.text = text - - -class TitledWin(CursesWin): - - def __init__(self, x, y, w, h, title): - super(TitledWin, self).__init__(x, y + 1, w, h - 1) - self.title = title - self.title_win = TextWin(x, y, w) - self.title_win.setText(title) - self.draw() - - def setTitle(self, title): - self.title_win.setText(title) - - def draw(self): - self.title_win.setReverse(self.getFocus()) - self.title_win.draw() - self.win.noutrefresh() - - -class ListWin(CursesWin): - - def __init__(self, x, y, w, h): - super(ListWin, self).__init__(x, y, w, h) - self.items = [] - self.selected = 0 - self.first_drawn = 0 - self.win.leaveok(True) - - def draw(self): - if len(self.items) == 0: - self.win.erase() - return - - h, w = self.win.getmaxyx() - - allLines = [] - firstSelected = -1 - lastSelected = -1 - for i, item in enumerate(self.items): - lines = self.items[i].split('\n') - lines = lines if lines[len(lines) - 1] != '' else lines[:-1] - if len(lines) == 0: - lines = [''] - - if i == self.getSelected(): - firstSelected = len(allLines) - allLines.extend(lines) - if i == self.selected: - lastSelected = len(allLines) - 1 - - if firstSelected < self.first_drawn: - self.first_drawn = firstSelected - elif lastSelected >= self.first_drawn + h: - self.first_drawn = lastSelected - h + 1 - - self.win.erase() - - begin = self.first_drawn - end = begin + h - - y = 0 - for i, line in list(enumerate(allLines))[begin:end]: - attr = curses.A_NORMAL - if i >= firstSelected and i <= lastSelected: - attr = curses.A_REVERSE - line = '{0:{width}}'.format(line, width=w - 1) - - # Ignore the error we get from drawing over the bottom-right char. - try: - self.win.addstr(y, 0, line[:w], attr) - except curses.error: - pass - y += 1 - self.win.noutrefresh() - - def getSelected(self): - if self.items: - return self.selected - return -1 - - def setSelected(self, selected): - self.selected = selected - if self.selected < 0: - self.selected = 0 - elif self.selected >= len(self.items): - self.selected = len(self.items) - 1 - - def handleEvent(self, event): - if isinstance(event, int): - if len(self.items) > 0: - if event == curses.KEY_UP: - self.setSelected(self.selected - 1) - if event == curses.KEY_DOWN: - self.setSelected(self.selected + 1) - if event == curses.ascii.NL: - self.handleSelect(self.selected) - - def addItem(self, item): - self.items.append(item) - - def clearItems(self): - self.items = [] - - def handleSelect(self, index): - return - - -class InputHandler(threading.Thread): - - def __init__(self, screen, queue): - super(InputHandler, self).__init__() - self.screen = screen - self.queue = queue - - def run(self): - while True: - c = self.screen.getch() - self.queue.put(c) - - -class CursesUI(object): - """ Responsible for updating the console UI with curses. """ - - def __init__(self, screen, event_queue): - self.screen = screen - self.event_queue = event_queue - - curses.start_color() - curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE) - curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK) - curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK) - self.screen.bkgd(curses.color_pair(1)) - self.screen.clear() - - self.input_handler = InputHandler(self.screen, self.event_queue) - self.input_handler.daemon = True - - self.focus = 0 - - self.screen.refresh() - - def focusNext(self): - self.wins[self.focus].setFocus(False) - old = self.focus - while True: - self.focus += 1 - if self.focus >= len(self.wins): - self.focus = 0 - if self.wins[self.focus].canFocus(): - break - self.wins[self.focus].setFocus(True) - - def handleEvent(self, event): - if isinstance(event, int): - if event == curses.KEY_F3: - self.focusNext() - - def eventLoop(self): - - self.input_handler.start() - self.wins[self.focus].setFocus(True) - - while True: - self.screen.noutrefresh() - - for i, win in enumerate(self.wins): - if i != self.focus: - win.draw() - # Draw the focused window last so that the cursor shows up. - if self.wins: - self.wins[self.focus].draw() - curses.doupdate() # redraw the physical screen - - event = self.event_queue.get() - - for win in self.wins: - if isinstance(event, int): - if win.getFocus() or not win.canFocus(): - win.handleEvent(event) - else: - win.handleEvent(event) - self.handleEvent(event) - - -class CursesEditLine(object): - """ Embed an 'editline'-compatible prompt inside a CursesWin. """ - - def __init__(self, win, history, enterCallback, tabCompleteCallback): - self.win = win - self.history = history - self.enterCallback = enterCallback - self.tabCompleteCallback = tabCompleteCallback - - self.prompt = '' - self.content = '' - self.index = 0 - self.startx = -1 - self.starty = -1 - - def draw(self, prompt=None): - if not prompt: - prompt = self.prompt - (h, w) = self.win.getmaxyx() - if (len(prompt) + len(self.content)) / w + self.starty >= h - 1: - self.win.scroll(1) - self.starty -= 1 - if self.starty < 0: - raise RuntimeError('Input too long; aborting') - (y, x) = (self.starty, self.startx) - - self.win.move(y, x) - self.win.clrtobot() - self.win.addstr(y, x, prompt) - remain = self.content - self.win.addstr(remain[:w - len(prompt)]) - remain = remain[w - len(prompt):] - while remain != '': - y += 1 - self.win.addstr(y, 0, remain[:w]) - remain = remain[w:] - - length = self.index + len(prompt) - self.win.move(self.starty + length / w, length % w) - - def showPrompt(self, y, x, prompt=None): - self.content = '' - self.index = 0 - self.startx = x - self.starty = y - self.draw(prompt) - - def handleEvent(self, event): - if not isinstance(event, int): - return # not handled - key = event - - if self.startx == -1: - raise RuntimeError('Trying to handle input without prompt') - - if key == curses.ascii.NL: - self.enterCallback(self.content) - elif key == curses.ascii.TAB: - self.tabCompleteCallback(self.content) - elif curses.ascii.isprint(key): - self.content = self.content[:self.index] + \ - chr(key) + self.content[self.index:] - self.index += 1 - elif key == curses.KEY_BACKSPACE or key == curses.ascii.BS: - if self.index > 0: - self.index -= 1 - self.content = self.content[ - :self.index] + self.content[self.index + 1:] - elif key == curses.KEY_DC or key == curses.ascii.DEL or key == curses.ascii.EOT: - self.content = self.content[ - :self.index] + self.content[self.index + 1:] - elif key == curses.ascii.VT: # CTRL-K - self.content = self.content[:self.index] - elif key == curses.KEY_LEFT or key == curses.ascii.STX: # left or CTRL-B - if self.index > 0: - self.index -= 1 - elif key == curses.KEY_RIGHT or key == curses.ascii.ACK: # right or CTRL-F - if self.index < len(self.content): - self.index += 1 - elif key == curses.ascii.SOH: # CTRL-A - self.index = 0 - elif key == curses.ascii.ENQ: # CTRL-E - self.index = len(self.content) - elif key == curses.KEY_UP or key == curses.ascii.DLE: # up or CTRL-P - self.content = self.history.previous(self.content) - self.index = len(self.content) - elif key == curses.KEY_DOWN or key == curses.ascii.SO: # down or CTRL-N - self.content = self.history.next() - self.index = len(self.content) - self.draw() diff --git a/lldb/utils/lui/debuggerdriver.py b/lldb/utils/lui/debuggerdriver.py deleted file mode 100644 index f94ce5face7..00000000000 --- a/lldb/utils/lui/debuggerdriver.py +++ /dev/null @@ -1,142 +0,0 @@ -##===-- 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 diff --git a/lldb/utils/lui/eventwin.py b/lldb/utils/lui/eventwin.py deleted file mode 100644 index c8d14d7aeb0..00000000000 --- a/lldb/utils/lui/eventwin.py +++ /dev/null @@ -1,26 +0,0 @@ -##===-- eventwin.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 cui -import lldb -import lldbutil - - -class EventWin(cui.TitledWin): - - def __init__(self, x, y, w, h): - super(EventWin, self).__init__(x, y, w, h, 'LLDB Event Log') - self.win.scrollok(1) - super(EventWin, self).draw() - - def handleEvent(self, event): - if isinstance(event, lldb.SBEvent): - self.win.scroll() - h = self.win.getmaxyx()[0] - self.win.addstr(h - 1, 0, lldbutil.get_description(event)) - return diff --git a/lldb/utils/lui/lldbutil.py b/lldb/utils/lui/lldbutil.py deleted file mode 100644 index 6bfaaecab4b..00000000000 --- a/lldb/utils/lui/lldbutil.py +++ /dev/null @@ -1,1040 +0,0 @@ -##===-- lldbutil.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 -## -##===----------------------------------------------------------------------===## - -""" -This LLDB module contains miscellaneous utilities. -Some of the test suite takes advantage of the utility functions defined here. -They can also be useful for general purpose lldb scripting. -""" - -from __future__ import print_function - -import lldb -import os -import sys -import io - -# =================================================== -# Utilities for locating/checking executable programs -# =================================================== - - -def is_exe(fpath): - """Returns True if fpath is an executable.""" - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - - -def which(program): - """Returns the full path to a program; None otherwise.""" - fpath, fname = os.path.split(program) - if fpath: - if is_exe(program): - return program - else: - for path in os.environ["PATH"].split(os.pathsep): - exe_file = os.path.join(path, program) - if is_exe(exe_file): - return exe_file - return None - -# =================================================== -# Disassembly for an SBFunction or an SBSymbol object -# =================================================== - - -def disassemble(target, function_or_symbol): - """Disassemble the function or symbol given a target. - - It returns the disassembly content in a string object. - """ - buf = io.StringIO() - insts = function_or_symbol.GetInstructions(target) - for i in insts: - print(i, file=buf) - return buf.getvalue() - -# ========================================================== -# Integer (byte size 1, 2, 4, and 8) to bytearray conversion -# ========================================================== - - -def int_to_bytearray(val, bytesize): - """Utility function to convert an integer into a bytearray. - - It returns the bytearray in the little endian format. It is easy to get the - big endian format, just do ba.reverse() on the returned object. - """ - import struct - - if bytesize == 1: - return bytearray([val]) - - # Little endian followed by a format character. - template = "<%c" - if bytesize == 2: - fmt = template % 'h' - elif bytesize == 4: - fmt = template % 'i' - elif bytesize == 4: - fmt = template % 'q' - else: - return None - - packed = struct.pack(fmt, val) - return bytearray(ord(x) for x in packed) - - -def bytearray_to_int(bytes, bytesize): - """Utility function to convert a bytearray into an integer. - - It interprets the bytearray in the little endian format. For a big endian - bytearray, just do ba.reverse() on the object before passing it in. - """ - import struct - - if bytesize == 1: - return bytes[0] - - # Little endian followed by a format character. - template = "<%c" - if bytesize == 2: - fmt = template % 'h' - elif bytesize == 4: - fmt = template % 'i' - elif bytesize == 4: - fmt = template % 'q' - else: - return None - - unpacked = struct.unpack(fmt, str(bytes)) - return unpacked[0] - - -# ============================================================== -# Get the description of an lldb object or None if not available -# ============================================================== -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() - - -# ================================================= -# Convert some enum value to its string counterpart -# ================================================= - -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") - - -def stop_reason_to_str(enum): - """Returns the stopReason string given an enum.""" - if enum == lldb.eStopReasonInvalid: - return "invalid" - elif enum == lldb.eStopReasonNone: - return "none" - elif enum == lldb.eStopReasonTrace: - return "trace" - elif enum == lldb.eStopReasonBreakpoint: - return "breakpoint" - elif enum == lldb.eStopReasonWatchpoint: - return "watchpoint" - elif enum == lldb.eStopReasonSignal: - return "signal" - elif enum == lldb.eStopReasonException: - return "exception" - elif enum == lldb.eStopReasonPlanComplete: - return "plancomplete" - elif enum == lldb.eStopReasonThreadExiting: - return "threadexiting" - else: - raise Exception("Unknown StopReason enum") - - -def symbol_type_to_str(enum): - """Returns the symbolType string given an enum.""" - if enum == lldb.eSymbolTypeInvalid: - return "invalid" - elif enum == lldb.eSymbolTypeAbsolute: - return "absolute" - elif enum == lldb.eSymbolTypeCode: - return "code" - elif enum == lldb.eSymbolTypeData: - return "data" - elif enum == lldb.eSymbolTypeTrampoline: - return "trampoline" - elif enum == lldb.eSymbolTypeRuntime: - return "runtime" - elif enum == lldb.eSymbolTypeException: - return "exception" - elif enum == lldb.eSymbolTypeSourceFile: - return "sourcefile" - elif enum == lldb.eSymbolTypeHeaderFile: - return "headerfile" - elif enum == lldb.eSymbolTypeObjectFile: - return "objectfile" - elif enum == lldb.eSymbolTypeCommonBlock: - return "commonblock" - elif enum == lldb.eSymbolTypeBlock: - return "block" - elif enum == lldb.eSymbolTypeLocal: - return "local" - elif enum == lldb.eSymbolTypeParam: - return "param" - elif enum == lldb.eSymbolTypeVariable: - return "variable" - elif enum == lldb.eSymbolTypeVariableType: - return "variabletype" - elif enum == lldb.eSymbolTypeLineEntry: - return "lineentry" - elif enum == lldb.eSymbolTypeLineHeader: - return "lineheader" - elif enum == lldb.eSymbolTypeScopeBegin: - return "scopebegin" - elif enum == lldb.eSymbolTypeScopeEnd: - return "scopeend" - elif enum == lldb.eSymbolTypeAdditional: - return "additional" - elif enum == lldb.eSymbolTypeCompiler: - return "compiler" - elif enum == lldb.eSymbolTypeInstrumentation: - return "instrumentation" - elif enum == lldb.eSymbolTypeUndefined: - return "undefined" - - -def value_type_to_str(enum): - """Returns the valueType string given an enum.""" - if enum == lldb.eValueTypeInvalid: - return "invalid" - elif enum == lldb.eValueTypeVariableGlobal: - return "global_variable" - elif enum == lldb.eValueTypeVariableStatic: - return "static_variable" - elif enum == lldb.eValueTypeVariableArgument: - return "argument_variable" - elif enum == lldb.eValueTypeVariableLocal: - return "local_variable" - elif enum == lldb.eValueTypeRegister: - return "register" - elif enum == lldb.eValueTypeRegisterSet: - return "register_set" - elif enum == lldb.eValueTypeConstResult: - return "constant_result" - else: - raise Exception("Unknown ValueType enum") - - -# ================================================== -# Get stopped threads due to each stop reason. -# ================================================== - -def sort_stopped_threads(process, - breakpoint_threads=None, - crashed_threads=None, - watchpoint_threads=None, - signal_threads=None, - exiting_threads=None, - other_threads=None): - """ Fills array *_threads with threads stopped for the corresponding stop - reason. - """ - for lst in [breakpoint_threads, - watchpoint_threads, - signal_threads, - exiting_threads, - other_threads]: - if lst is not None: - lst[:] = [] - - for thread in process: - dispatched = False - for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads), - (lldb.eStopReasonException, crashed_threads), - (lldb.eStopReasonWatchpoint, watchpoint_threads), - (lldb.eStopReasonSignal, signal_threads), - (lldb.eStopReasonThreadExiting, exiting_threads), - (None, other_threads)]: - if not dispatched and list is not None: - if thread.GetStopReason() == reason or reason is None: - list.append(thread) - dispatched = True - -# ================================================== -# Utility functions for setting breakpoints -# ================================================== - - -def run_break_set_by_file_and_line( - test, - file_name, - line_number, - extra_options=None, - num_expected_locations=1, - loc_exact=False, - module_name=None): - """Set a breakpoint by file and line, returning the breakpoint number. - - If extra_options is not None, then we append it to the breakpoint set command. - - If num_expected_locations is -1 we check that we got AT LEAST one location, otherwise we check that num_expected_locations equals the number of locations. - - If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.""" - - if file_name is None: - command = 'breakpoint set -l %d' % (line_number) - else: - command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) - - if module_name: - command += " --shlib '%s'" % (module_name) - - if extra_options: - command += " " + extra_options - - break_results = run_break_set_command(test, command) - - if num_expected_locations == 1 and loc_exact: - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations, - file_name=file_name, - line_number=line_number, - module_name=module_name) - else: - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) - - return get_bpno_from_match(break_results) - - -def run_break_set_by_symbol( - test, - symbol, - extra_options=None, - num_expected_locations=-1, - sym_exact=False, - module_name=None): - """Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line. - - If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.""" - command = 'breakpoint set -n "%s"' % (symbol) - - if module_name: - command += " --shlib '%s'" % (module_name) - - if extra_options: - command += " " + extra_options - - break_results = run_break_set_command(test, command) - - if num_expected_locations == 1 and sym_exact: - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations, - symbol_name=symbol, - module_name=module_name) - else: - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) - - return get_bpno_from_match(break_results) - - -def run_break_set_by_selector( - test, - selector, - extra_options=None, - num_expected_locations=-1, - module_name=None): - """Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line.""" - - command = 'breakpoint set -S "%s"' % (selector) - - if module_name: - command += ' --shlib "%s"' % (module_name) - - if extra_options: - command += " " + extra_options - - break_results = run_break_set_command(test, command) - - if num_expected_locations == 1: - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations, - symbol_name=selector, - symbol_match_exact=False, - module_name=module_name) - else: - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) - - return get_bpno_from_match(break_results) - - -def run_break_set_by_regexp( - test, - regexp, - extra_options=None, - num_expected_locations=-1): - """Set a breakpoint by regular expression match on symbol name. Common options are the same as run_break_set_by_file_and_line.""" - - command = 'breakpoint set -r "%s"' % (regexp) - if extra_options: - command += " " + extra_options - - break_results = run_break_set_command(test, command) - - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) - - return get_bpno_from_match(break_results) - - -def run_break_set_by_source_regexp( - test, - regexp, - extra_options=None, - num_expected_locations=-1): - """Set a breakpoint by source regular expression. Common options are the same as run_break_set_by_file_and_line.""" - command = 'breakpoint set -p "%s"' % (regexp) - if extra_options: - command += " " + extra_options - - break_results = run_break_set_command(test, command) - - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) - - return get_bpno_from_match(break_results) - - -def run_break_set_command(test, command): - """Run the command passed in - it must be some break set variant - and analyze the result. - Returns a dictionary of information gleaned from the command-line results. - Will assert if the breakpoint setting fails altogether. - - Dictionary will contain: - bpno - breakpoint of the newly created breakpoint, -1 on error. - num_locations - number of locations set for the breakpoint. - - If there is only one location, the dictionary MAY contain: - file - source file name - line_no - source line number - symbol - symbol name - inline_symbol - inlined symbol name - offset - offset from the original symbol - module - module - address - address at which the breakpoint was set.""" - - patterns = [ - r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$", - r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", - r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$", - r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"] - match_object = test.match(command, patterns) - break_results = match_object.groupdict() - - # We always insert the breakpoint number, setting it to -1 if we couldn't find it - # Also, make sure it gets stored as an integer. - if not 'bpno' in break_results: - break_results['bpno'] = -1 - else: - break_results['bpno'] = int(break_results['bpno']) - - # We always insert the number of locations - # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1... - # We also make sure it is an integer. - - if not 'num_locations' in break_results: - num_locations = 1 - else: - num_locations = break_results['num_locations'] - if num_locations == 'no': - num_locations = 0 - else: - num_locations = int(break_results['num_locations']) - - break_results['num_locations'] = num_locations - - if 'line_no' in break_results: - break_results['line_no'] = int(break_results['line_no']) - - return break_results - - -def get_bpno_from_match(break_results): - return int(break_results['bpno']) - - -def check_breakpoint_result( - test, - break_results, - file_name=None, - line_number=-1, - symbol_name=None, - symbol_match_exact=True, - module_name=None, - offset=-1, - num_locations=-1): - - out_num_locations = break_results['num_locations'] - - if num_locations == -1: - test.assertTrue(out_num_locations > 0, - "Expecting one or more locations, got none.") - else: - test.assertTrue( - num_locations == out_num_locations, - "Expecting %d locations, got %d." % - (num_locations, - out_num_locations)) - - if file_name: - out_file_name = "" - if 'file' in break_results: - out_file_name = break_results['file'] - test.assertTrue( - file_name == out_file_name, - "Breakpoint file name '%s' doesn't match resultant name '%s'." % - (file_name, - out_file_name)) - - if line_number != -1: - out_file_line = -1 - if 'line_no' in break_results: - out_line_number = break_results['line_no'] - - test.assertTrue( - line_number == out_line_number, - "Breakpoint line number %s doesn't match resultant line %s." % - (line_number, - out_line_number)) - - if symbol_name: - out_symbol_name = "" - # Look first for the inlined symbol name, otherwise use the symbol - # name: - if 'inline_symbol' in break_results and break_results['inline_symbol']: - out_symbol_name = break_results['inline_symbol'] - elif 'symbol' in break_results: - out_symbol_name = break_results['symbol'] - - if symbol_match_exact: - test.assertTrue( - symbol_name == out_symbol_name, - "Symbol name '%s' doesn't match resultant symbol '%s'." % - (symbol_name, - out_symbol_name)) - else: - test.assertTrue( - out_symbol_name.find(symbol_name) != - - 1, - "Symbol name '%s' isn't in resultant symbol '%s'." % - (symbol_name, - out_symbol_name)) - - if module_name: - out_nodule_name = None - if 'module' in break_results: - out_module_name = break_results['module'] - - test.assertTrue( - module_name.find(out_module_name) != - - 1, - "Symbol module name '%s' isn't in expected module name '%s'." % - (out_module_name, - module_name)) - -# ================================================== -# Utility functions related to Threads and Processes -# ================================================== - - -def get_stopped_threads(process, reason): - """Returns the thread(s) with the specified stop reason in a list. - - The list can be empty if no such thread exists. - """ - threads = [] - for t in process: - if t.GetStopReason() == reason: - threads.append(t) - return threads - - -def get_stopped_thread(process, reason): - """A convenience function which returns the first thread with the given stop - reason or None. - - Example usages: - - 1. Get the stopped thread due to a breakpoint condition - - ... - from lldbutil import get_stopped_thread - thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete) - self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition") - ... - - 2. Get the thread stopped due to a breakpoint - - ... - from lldbutil import get_stopped_thread - thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) - self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint") - ... - - """ - threads = get_stopped_threads(process, reason) - if len(threads) == 0: - return None - return threads[0] - - -def get_threads_stopped_at_breakpoint(process, bkpt): - """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" - stopped_threads = [] - threads = [] - - stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint) - - if len(stopped_threads) == 0: - return threads - - for thread in stopped_threads: - # Make sure we've hit our breakpoint... - break_id = thread.GetStopReasonDataAtIndex(0) - if break_id == bkpt.GetID(): - threads.append(thread) - - return threads - - -def continue_to_breakpoint(process, bkpt): - """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" - process.Continue() - if process.GetState() != lldb.eStateStopped: - return None - else: - return get_threads_stopped_at_breakpoint(process, bkpt) - - -def get_caller_symbol(thread): - """ - Returns the symbol name for the call site of the leaf function. - """ - depth = thread.GetNumFrames() - if depth <= 1: - return None - caller = thread.GetFrameAtIndex(1).GetSymbol() - if caller: - return caller.GetName() - else: - return None - - -def get_function_names(thread): - """ - Returns a sequence of function names from the stack frames of this thread. - """ - def GetFuncName(i): - return thread.GetFrameAtIndex(i).GetFunctionName() - - return [GetFuncName(i) for i in range(thread.GetNumFrames())] - - -def get_symbol_names(thread): - """ - Returns a sequence of symbols for this thread. - """ - def GetSymbol(i): - return thread.GetFrameAtIndex(i).GetSymbol().GetName() - - return [GetSymbol(i) for i in range(thread.GetNumFrames())] - - -def get_pc_addresses(thread): - """ - Returns a sequence of pc addresses for this thread. - """ - def GetPCAddress(i): - return thread.GetFrameAtIndex(i).GetPCAddress() - - return [GetPCAddress(i) for i in range(thread.GetNumFrames())] - - -def get_filenames(thread): - """ - Returns a sequence of file names from the stack frames of this thread. - """ - def GetFilename(i): - return thread.GetFrameAtIndex( - i).GetLineEntry().GetFileSpec().GetFilename() - - return [GetFilename(i) for i in range(thread.GetNumFrames())] - - -def get_line_numbers(thread): - """ - Returns a sequence of line numbers from the stack frames of this thread. - """ - def GetLineNumber(i): - return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() - - return [GetLineNumber(i) for i in range(thread.GetNumFrames())] - - -def get_module_names(thread): - """ - Returns a sequence of module names from the stack frames of this thread. - """ - def GetModuleName(i): - return thread.GetFrameAtIndex( - i).GetModule().GetFileSpec().GetFilename() - - return [GetModuleName(i) for i in range(thread.GetNumFrames())] - - -def get_stack_frames(thread): - """ - Returns a sequence of stack frames for this thread. - """ - def GetStackFrame(i): - return thread.GetFrameAtIndex(i) - - return [GetStackFrame(i) for i in range(thread.GetNumFrames())] - - -def print_stacktrace(thread, string_buffer=False): - """Prints a simple stack trace of this thread.""" - - output = io.StringIO() if string_buffer else sys.stdout - target = thread.GetProcess().GetTarget() - - depth = thread.GetNumFrames() - - mods = get_module_names(thread) - funcs = get_function_names(thread) - symbols = get_symbol_names(thread) - files = get_filenames(thread) - lines = get_line_numbers(thread) - addrs = get_pc_addresses(thread) - - if thread.GetStopReason() != lldb.eStopReasonInvalid: - desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) - else: - desc = "" - print("Stack trace for thread id={0:#x} name={1} queue={2} ".format( - thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc, file=output) - - for i in range(depth): - frame = thread.GetFrameAtIndex(i) - function = frame.GetFunction() - - load_addr = addrs[i].GetLoadAddress(target) - if not function: - file_addr = addrs[i].GetFileAddress() - start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress() - symbol_offset = file_addr - start_addr - print(" frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format( - num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset), file=output) - else: - print(" frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format( - num=i, addr=load_addr, mod=mods[i], func='%s [inlined]' % - funcs[i] if frame.IsInlined() else funcs[i], file=files[i], line=lines[i], args=get_args_as_string( - frame, showFuncName=False) if not frame.IsInlined() else '()'), file=output) - - if string_buffer: - return output.getvalue() - - -def print_stacktraces(process, string_buffer=False): - """Prints the stack traces of all the threads.""" - - output = io.StringIO() if string_buffer else sys.stdout - - print("Stack traces for " + str(process), file=output) - - for thread in process: - print(print_stacktrace(thread, string_buffer=True), file=output) - - if string_buffer: - return output.getvalue() - -# =================================== -# Utility functions related to Frames -# =================================== - - -def get_parent_frame(frame): - """ - Returns the parent frame of the input frame object; None if not available. - """ - thread = frame.GetThread() - parent_found = False - for f in thread: - if parent_found: - return f - if f.GetFrameID() == frame.GetFrameID(): - parent_found = True - - # If we reach here, no parent has been found, return None. - return None - - -def get_args_as_string(frame, showFuncName=True): - """ - Returns the args of the input frame object as a string. - """ - # arguments => True - # locals => False - # statics => False - # in_scope_only => True - vars = frame.GetVariables(True, False, False, True) # type of SBValueList - args = [] # list of strings - for var in vars: - args.append("(%s)%s=%s" % (var.GetTypeName(), - var.GetName(), - var.GetValue())) - if frame.GetFunction(): - name = frame.GetFunction().GetName() - elif frame.GetSymbol(): - name = frame.GetSymbol().GetName() - else: - name = "" - if showFuncName: - return "%s(%s)" % (name, ", ".join(args)) - else: - return "(%s)" % (", ".join(args)) - - -def print_registers(frame, string_buffer=False): - """Prints all the register sets of the frame.""" - - output = io.StringIO() if string_buffer else sys.stdout - - print("Register sets for " + str(frame), file=output) - - registerSet = frame.GetRegisters() # Return type of SBValueList. - print("Frame registers (size of register set = %d):" % registerSet.GetSize( - ), file=output) - for value in registerSet: - #print >> output, value - print("%s (number of children = %d):" % ( - value.GetName(), value.GetNumChildren()), file=output) - for child in value: - print("Name: %s, Value: %s" % ( - child.GetName(), child.GetValue()), file=output) - - if string_buffer: - return output.getvalue() - - -def get_registers(frame, kind): - """Returns the registers given the frame and the kind of registers desired. - - Returns None if there's no such kind. - """ - registerSet = frame.GetRegisters() # Return type of SBValueList. - for value in registerSet: - if kind.lower() in value.GetName().lower(): - return value - - return None - - -def get_GPRs(frame): - """Returns the general purpose registers of the frame as an SBValue. - - The returned SBValue object is iterable. An example: - ... - from lldbutil import get_GPRs - regs = get_GPRs(frame) - for reg in regs: - print "%s => %s" % (reg.GetName(), reg.GetValue()) - ... - """ - return get_registers(frame, "general purpose") - - -def get_FPRs(frame): - """Returns the floating point registers of the frame as an SBValue. - - The returned SBValue object is iterable. An example: - ... - from lldbutil import get_FPRs - regs = get_FPRs(frame) - for reg in regs: - print "%s => %s" % (reg.GetName(), reg.GetValue()) - ... - """ - return get_registers(frame, "floating point") - - -def get_ESRs(frame): - """Returns the exception state registers of the frame as an SBValue. - - The returned SBValue object is iterable. An example: - ... - from lldbutil import get_ESRs - regs = get_ESRs(frame) - for reg in regs: - print "%s => %s" % (reg.GetName(), reg.GetValue()) - ... - """ - return get_registers(frame, "exception state") - -# ====================================== -# Utility classes/functions for SBValues -# ====================================== - - -class BasicFormatter(object): - """The basic formatter inspects the value object and prints the value.""" - - def format(self, value, buffer=None, indent=0): - if not buffer: - output = io.StringIO() - else: - output = buffer - # If there is a summary, it suffices. - val = value.GetSummary() - # Otherwise, get the value. - if val is None: - val = value.GetValue() - if val is None and value.GetNumChildren() > 0: - val = "%s (location)" % value.GetLocation() - print("{indentation}({type}) {name} = {value}".format( - indentation=' ' * indent, - type=value.GetTypeName(), - name=value.GetName(), - value=val), file=output) - return output.getvalue() - - -class ChildVisitingFormatter(BasicFormatter): - """The child visiting formatter prints the value and its immediate children. - - The constructor takes a keyword arg: indent_child, which defaults to 2. - """ - - def __init__(self, indent_child=2): - """Default indentation of 2 SPC's for the children.""" - self.cindent = indent_child - - def format(self, value, buffer=None): - if not buffer: - output = io.StringIO() - else: - output = buffer - - BasicFormatter.format(self, value, buffer=output) - for child in value: - BasicFormatter.format( - self, child, buffer=output, indent=self.cindent) - - return output.getvalue() - - -class RecursiveDecentFormatter(BasicFormatter): - """The recursive decent formatter prints the value and the decendents. - - The constructor takes two keyword args: indent_level, which defaults to 0, - and indent_child, which defaults to 2. The current indentation level is - determined by indent_level, while the immediate children has an additional - indentation by inden_child. - """ - - def __init__(self, indent_level=0, indent_child=2): - self.lindent = indent_level - self.cindent = indent_child - - def format(self, value, buffer=None): - if not buffer: - output = io.StringIO() - else: - output = buffer - - BasicFormatter.format(self, value, buffer=output, indent=self.lindent) - new_indent = self.lindent + self.cindent - for child in value: - if child.GetSummary() is not None: - BasicFormatter.format( - self, child, buffer=output, indent=new_indent) - else: - if child.GetNumChildren() > 0: - rdf = RecursiveDecentFormatter(indent_level=new_indent) - rdf.format(child, buffer=output) - else: - BasicFormatter.format( - self, child, buffer=output, indent=new_indent) - - return output.getvalue() diff --git a/lldb/utils/lui/lui.py b/lldb/utils/lui/lui.py deleted file mode 100755 index 98e1c63ce41..00000000000 --- a/lldb/utils/lui/lui.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python -##===-- lui.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 curses - -import lldb -import lldbutil - -from optparse import OptionParser -import os -import signal -import sys - -try: - import queue -except ImportError: - import Queue as queue - -import debuggerdriver -import cui - -import breakwin -import commandwin -import eventwin -import sourcewin -import statuswin - -event_queue = None - - -def handle_args(driver, argv): - parser = OptionParser() - parser.add_option( - "-p", - "--attach", - dest="pid", - help="Attach to specified Process ID", - type="int") - parser.add_option( - "-c", - "--core", - dest="core", - help="Load specified core file", - type="string") - - (options, args) = parser.parse_args(argv) - - if options.pid is not None: - try: - pid = int(options.pid) - driver.attachProcess(ui, pid) - except ValueError: - print("Error: expecting integer PID, got '%s'" % options.pid) - elif options.core is not None: - if not os.path.exists(options.core): - raise Exception( - "Specified core file '%s' does not exist." % - options.core) - driver.loadCore(options.core) - elif len(args) == 2: - if not os.path.isfile(args[1]): - raise Exception("Specified target '%s' does not exist" % args[1]) - driver.createTarget(args[1]) - elif len(args) > 2: - if not os.path.isfile(args[1]): - raise Exception("Specified target '%s' does not exist" % args[1]) - driver.createTarget(args[1], args[2:]) - - -def sigint_handler(signal, frame): - global debugger - debugger.terminate() - - -class LLDBUI(cui.CursesUI): - - def __init__(self, screen, event_queue, driver): - super(LLDBUI, self).__init__(screen, event_queue) - - self.driver = driver - - h, w = self.screen.getmaxyx() - - command_win_height = 20 - break_win_width = 60 - - self.status_win = statuswin.StatusWin(0, h - 1, w, 1) - h -= 1 - self.command_win = commandwin.CommandWin( - driver, 0, h - command_win_height, w, command_win_height) - h -= command_win_height - self.source_win = sourcewin.SourceWin(driver, 0, 0, - w - break_win_width - 1, h) - self.break_win = breakwin.BreakWin(driver, w - break_win_width, 0, - break_win_width, h) - - self.wins = [self.status_win, - # self.event_win, - self.source_win, - self.break_win, - self.command_win, - ] - - self.focus = len(self.wins) - 1 # index of command window; - - def handleEvent(self, event): - # hack - if isinstance(event, int): - if event == curses.KEY_F10: - self.driver.terminate() - if event == 20: # ctrl-T - def foo(cmd): - ret = lldb.SBCommandReturnObject() - self.driver.getCommandInterpreter().HandleCommand(cmd, ret) - foo('target create a.out') - foo('b main') - foo('run') - super(LLDBUI, self).handleEvent(event) - - -def main(screen): - signal.signal(signal.SIGINT, sigint_handler) - - global event_queue - event_queue = queue.Queue() - - global debugger - debugger = lldb.SBDebugger.Create() - - driver = debuggerdriver.createDriver(debugger, event_queue) - view = LLDBUI(screen, event_queue, driver) - - driver.start() - - # hack to avoid hanging waiting for prompts! - driver.handleCommand("settings set auto-confirm true") - - handle_args(driver, sys.argv) - view.eventLoop() - -if __name__ == "__main__": - try: - curses.wrapper(main) - except KeyboardInterrupt: - exit() diff --git a/lldb/utils/lui/sandbox.py b/lldb/utils/lui/sandbox.py deleted file mode 100755 index 8bb4e3595f8..00000000000 --- a/lldb/utils/lui/sandbox.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python -##===-- sandbox.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 curses - -import os -import signal -import sys - -try: - import queue -except ImportError: - import Queue as queue - -import cui - -event_queue = None - - -class SandboxUI(cui.CursesUI): - - def __init__(self, screen, event_queue): - super(SandboxUI, self).__init__(screen, event_queue) - - height, width = self.screen.getmaxyx() - w2 = width / 2 - h2 = height / 2 - - self.wins = [] - #self.wins.append(cui.TitledWin(w2, h2, w2, h2, "Test Window 4")) - list_win = cui.ListWin(w2, h2, w2, h2) - for i in range(0, 40): - list_win.addItem('Item %s' % i) - self.wins.append(list_win) - self.wins.append(cui.TitledWin(0, 0, w2, h2, "Test Window 1")) - self.wins.append(cui.TitledWin(w2, 0, w2, h2, "Test Window 2")) - self.wins.append(cui.TitledWin(0, h2, w2, h2, "Test Window 3")) - - # def callback(s, content): - # self.wins[0].win.scroll(1) - # self.wins[0].win.addstr(10, 0, '%s: %s' % (s, content)) - # self.wins[0].win.scroll(1) - # self.el.showPrompt(10, 0) - - # self.wins[0].win.scrollok(1) - # self.el = cui.CursesEditLine(self.wins[0].win, None, - # lambda c: callback('got', c), lambda c: callback('tab', c)) - #self.el.prompt = '>>> ' - #self.el.showPrompt(10, 0) - - def handleEvent(self, event): - if isinstance(event, int): - if event == ord('q'): - sys.exit(0) - # self.el.handleEvent(event) - super(SandboxUI, self).handleEvent(event) - - -def main(screen): - global event_queue - event_queue = queue.Queue() - - sandbox = SandboxUI(screen, event_queue) - sandbox.eventLoop() - -if __name__ == "__main__": - try: - curses.wrapper(main) - except KeyboardInterrupt: - exit() diff --git a/lldb/utils/lui/sourcewin.py b/lldb/utils/lui/sourcewin.py deleted file mode 100644 index c3add058f12..00000000000 --- a/lldb/utils/lui/sourcewin.py +++ /dev/null @@ -1,238 +0,0 @@ -##===-- sourcewin.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 cui -import curses -import lldb -import lldbutil -import re -import os - - -class SourceWin(cui.TitledWin): - - def __init__(self, driver, x, y, w, h): - super(SourceWin, self).__init__(x, y, w, h, "Source") - self.sourceman = driver.getSourceManager() - self.sources = {} - - self.filename = None - self.pc_line = None - self.viewline = 0 - - self.breakpoints = {} - - self.win.scrollok(1) - - self.markerPC = ":) " - self.markerBP = "B> " - self.markerNone = " " - - try: - from pygments.formatters import TerminalFormatter - self.formatter = TerminalFormatter() - except ImportError: - #self.win.addstr("\nWarning: no 'pygments' library found. Syntax highlighting is disabled.") - self.lexer = None - self.formatter = None - pass - - # FIXME: syntax highlight broken - self.formatter = None - self.lexer = None - - def handleEvent(self, event): - if isinstance(event, int): - self.handleKey(event) - return - - if isinstance(event, lldb.SBEvent): - if lldb.SBBreakpoint.EventIsBreakpointEvent(event): - self.handleBPEvent(event) - - if lldb.SBProcess.EventIsProcessEvent(event) and \ - not lldb.SBProcess.GetRestartedFromEvent(event): - process = lldb.SBProcess.GetProcessFromEvent(event) - if not process.IsValid(): - return - if process.GetState() == lldb.eStateStopped: - self.refreshSource(process) - elif process.GetState() == lldb.eStateExited: - self.notifyExited(process) - - def notifyExited(self, process): - self.win.erase() - target = lldbutil.get_description(process.GetTarget()) - pid = process.GetProcessID() - ec = process.GetExitStatus() - self.win.addstr( - "\nProcess %s [%d] has exited with exit-code %d" % - (target, pid, ec)) - - def pageUp(self): - if self.viewline > 0: - self.viewline = self.viewline - 1 - self.refreshSource() - - def pageDown(self): - if self.viewline < len(self.content) - self.height + 1: - self.viewline = self.viewline + 1 - self.refreshSource() - pass - - def handleKey(self, key): - if key == curses.KEY_DOWN: - self.pageDown() - elif key == curses.KEY_UP: - self.pageUp() - - def updateViewline(self): - half = self.height / 2 - if self.pc_line < half: - self.viewline = 0 - else: - self.viewline = self.pc_line - half + 1 - - if self.viewline < 0: - raise Exception( - "negative viewline: pc=%d viewline=%d" % - (self.pc_line, self.viewline)) - - def refreshSource(self, process=None): - (self.height, self.width) = self.win.getmaxyx() - - if process is not None: - loc = process.GetSelectedThread().GetSelectedFrame().GetLineEntry() - f = loc.GetFileSpec() - self.pc_line = loc.GetLine() - - if not f.IsValid(): - self.win.addstr(0, 0, "Invalid source file") - return - - self.filename = f.GetFilename() - path = os.path.join(f.GetDirectory(), self.filename) - self.setTitle(path) - self.content = self.getContent(path) - self.updateViewline() - - if self.filename is None: - return - - if self.formatter is not None: - from pygments.lexers import get_lexer_for_filename - self.lexer = get_lexer_for_filename(self.filename) - - bps = [] if not self.filename in self.breakpoints else self.breakpoints[self.filename] - self.win.erase() - if self.content: - self.formatContent(self.content, self.pc_line, bps) - - def getContent(self, path): - content = [] - if path in self.sources: - content = self.sources[path] - else: - if os.path.exists(path): - with open(path) as x: - content = x.readlines() - self.sources[path] = content - return content - - def formatContent(self, content, pc_line, breakpoints): - source = "" - count = 1 - self.win.erase() - end = min(len(content), self.viewline + self.height) - for i in range(self.viewline, end): - line_num = i + 1 - marker = self.markerNone - attr = curses.A_NORMAL - if line_num == pc_line: - attr = curses.A_REVERSE - if line_num in breakpoints: - marker = self.markerBP - line = "%s%3d %s" % (marker, line_num, self.highlight(content[i])) - if len(line) >= self.width: - line = line[0:self.width - 1] + "\n" - self.win.addstr(line, attr) - source += line - count = count + 1 - return source - - def highlight(self, source): - if self.lexer and self.formatter: - from pygments import highlight - return highlight(source, self.lexer, self.formatter) - else: - return source - - def addBPLocations(self, locations): - for path in locations: - lines = locations[path] - if path in self.breakpoints: - self.breakpoints[path].update(lines) - else: - self.breakpoints[path] = lines - - def removeBPLocations(self, locations): - for path in locations: - lines = locations[path] - if path in self.breakpoints: - self.breakpoints[path].difference_update(lines) - else: - raise "Removing locations that were never added...no good" - - def handleBPEvent(self, event): - def getLocations(event): - locs = {} - - bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event) - - if bp.IsInternal(): - # don't show anything for internal breakpoints - return - - for location in bp: - # hack! getting the LineEntry via SBBreakpointLocation.GetAddress.GetLineEntry does not work good for - # inlined frames, so we get the description (which does take - # into account inlined functions) and parse it. - desc = lldbutil.get_description( - location, lldb.eDescriptionLevelFull) - match = re.search('at\ ([^:]+):([\d]+)', desc) - try: - path = match.group(1) - line = int(match.group(2).strip()) - except ValueError as e: - # bp loc unparsable - continue - - if path in locs: - locs[path].add(line) - else: - locs[path] = set([line]) - return locs - - event_type = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event) - if event_type == lldb.eBreakpointEventTypeEnabled \ - or event_type == lldb.eBreakpointEventTypeAdded \ - or event_type == lldb.eBreakpointEventTypeLocationsResolved \ - or event_type == lldb.eBreakpointEventTypeLocationsAdded: - self.addBPLocations(getLocations(event)) - elif event_type == lldb.eBreakpointEventTypeRemoved \ - or event_type == lldb.eBreakpointEventTypeLocationsRemoved \ - or event_type == lldb.eBreakpointEventTypeDisabled: - self.removeBPLocations(getLocations(event)) - elif event_type == lldb.eBreakpointEventTypeCommandChanged \ - or event_type == lldb.eBreakpointEventTypeConditionChanged \ - or event_type == lldb.eBreakpointEventTypeIgnoreChanged \ - or event_type == lldb.eBreakpointEventTypeThreadChanged \ - or event_type == lldb.eBreakpointEventTypeInvalidType: - # no-op - pass - self.refreshSource() diff --git a/lldb/utils/lui/statuswin.py b/lldb/utils/lui/statuswin.py deleted file mode 100644 index 2d3cc217c01..00000000000 --- a/lldb/utils/lui/statuswin.py +++ /dev/null @@ -1,41 +0,0 @@ -##===-- statuswin.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 cui -import curses - - -class StatusWin(cui.TextWin): - - def __init__(self, x, y, w, h): - super(StatusWin, self).__init__(x, y, w) - - self.keys = [ # ('F1', 'Help', curses.KEY_F1), - ('F3', 'Cycle-focus', curses.KEY_F3), - ('F10', 'Quit', curses.KEY_F10)] - - def draw(self): - self.win.addstr(0, 0, '') - for key in self.keys: - self.win.addstr('{0}'.format(key[0]), curses.A_REVERSE) - self.win.addstr(' {0} '.format(key[1]), curses.A_NORMAL) - super(StatusWin, self).draw() - - def handleEvent(self, event): - if isinstance(event, int): - pass - elif isinstance(event, lldb.SBEvent): - if lldb.SBProcess.EventIsProcessEvent(event): - state = lldb.SBProcess.GetStateFromEvent(event) - status = lldbutil.state_type_to_str(state) - self.win.erase() - x = self.win.getmaxyx()[1] - len(status) - 1 - self.win.addstr(0, x, status) - return |

