diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
commit | 14f1b3e8826ce43b978db93a62d1166055db5394 (patch) | |
tree | 0a00ad8d3498783fe0193f3b656bca17c4c8697d /utils | |
parent | 4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff) | |
download | src-14f1b3e8826ce43b978db93a62d1166055db5394.tar.gz src-14f1b3e8826ce43b978db93a62d1166055db5394.zip |
Vendor import of lldb trunk r290819:vendor/lldb/lldb-trunk-r290819
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=311128
svn path=/vendor/lldb/lldb-trunk-r290819/; revision=311129; tag=vendor/lldb/lldb-trunk-r290819
Diffstat (limited to 'utils')
29 files changed, 2779 insertions, 2292 deletions
diff --git a/utils/git-svn/convert.py b/utils/git-svn/convert.py index c230a016b7f0..589522c78b3c 100755 --- a/utils/git-svn/convert.py +++ b/utils/git-svn/convert.py @@ -11,15 +11,19 @@ Usage: 4. git svn dcommit [--commit-url https://id@llvm.org/svn/llvm-project/lldb/trunk] """ -import os, re, sys +import os +import re +import sys import StringIO + def usage(problem_file=None): if problem_file: print "%s is not a file" % problem_file print "Usage: convert.py raw-message-source [raw-message-source2 ...]" sys.exit(0) + def do_convert(file): """Skip all preceding mail message headers until 'From: ' is encountered. Then for each line ('From: ' header included), replace the dos style CRLF @@ -38,7 +42,8 @@ def do_convert(file): # By default, splitlines() don't include line breaks. CRLF should be gone. for line in content.splitlines(): - # Wait till we scan the 'From: ' header before start printing the lines. + # Wait till we scan the 'From: ' header before start printing the + # lines. if not from_header_seen: if not line.startswith('From: '): continue @@ -52,6 +57,7 @@ def do_convert(file): print "done" + def main(): if len(sys.argv) == 1: usage() diff --git a/utils/lui/breakwin.py b/utils/lui/breakwin.py index 734f5eddba42..7ecb78fd1032 100644 --- a/utils/lui/breakwin.py +++ b/utils/lui/breakwin.py @@ -1,90 +1,94 @@ ##===-- breakwin.py ------------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## import cui import curses -import lldb, lldbutil +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): + def __init__(self, driver, x, y, w, h): + super(BreakWin, self).__init__(x, y, w, h) + self.driver = driver 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) + self.showDetails = {} - 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 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 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 + 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) + 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/utils/lui/commandwin.py b/utils/lui/commandwin.py index 2eb2082c6c80..f778d736ec53 100644 --- a/utils/lui/commandwin.py +++ b/utils/lui/commandwin.py @@ -1,9 +1,9 @@ ##===-- commandwin.py ----------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## @@ -12,110 +12,120 @@ 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 + + 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:") + + 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) - 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() + 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/utils/lui/cui.py b/utils/lui/cui.py index e82f0abac2cc..963606a0d529 100755 --- a/utils/lui/cui.py +++ b/utils/lui/cui.py @@ -1,9 +1,9 @@ ##===-- cui.py -----------------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## @@ -11,310 +11,329 @@ 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 + + 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 + + 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 __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() - 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 + + 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) + 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) + """ Responsible for updating the console UI with curses. """ - def handleEvent(self, event): - if isinstance(event, int): - if event == curses.KEY_F3: - self.focusNext() + def __init__(self, screen, event_queue): + self.screen = screen + self.event_queue = event_queue - def eventLoop(self): + 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.start() - self.wins[self.focus].setFocus(True) + self.input_handler = InputHandler(self.screen, self.event_queue) + self.input_handler.daemon = True - while True: - self.screen.noutrefresh() + self.focus = 0 - 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 + self.screen.refresh() - event = self.event_queue.get() + 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) - for win in self.wins: + def handleEvent(self, event): if isinstance(event, int): - if win.getFocus() or not win.canFocus(): - win.handleEvent(event) - else: - win.handleEvent(event) - self.handleEvent(event) + 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() + """ 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/utils/lui/debuggerdriver.py b/utils/lui/debuggerdriver.py index f7b885107cc6..48de10d79f3e 100644 --- a/utils/lui/debuggerdriver.py +++ b/utils/lui/debuggerdriver.py @@ -1,9 +1,9 @@ ##===-- debuggerdriver.py ------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## @@ -13,12 +13,15 @@ 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 + # This is probably not great because it does not give liblldb a chance + # to clean up self.daemon = True self.initialize(debugger) @@ -30,44 +33,45 @@ class DebuggerDriver(Thread): 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 - ) + 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 - ) + 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 - ) + 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 - ) + 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) + self.handleCommand("settings set target.run-args %s" % args) def attachProcess(self, pid): self.handleCommand("process attach -p %d" % pid) @@ -123,9 +127,10 @@ class DebuggerDriver(Thread): lldb.SBDebugger.Terminate() sys.exit(0) + def createDriver(debugger, event_queue): driver = DebuggerDriver(debugger, event_queue) - #driver.start() + # driver.start() # if pid specified: # - attach to pid # else if core file specified diff --git a/utils/lui/eventwin.py b/utils/lui/eventwin.py index 327978a3b456..8ad8d3a8c49e 100644 --- a/utils/lui/eventwin.py +++ b/utils/lui/eventwin.py @@ -1,25 +1,27 @@ ##===-- eventwin.py ------------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## import cui -import lldb, lldbutil +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 + 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/utils/lui/lldbutil.py b/utils/lui/lldbutil.py index 8bdb074728f3..b88a10a44fb9 100644 --- a/utils/lui/lldbutil.py +++ b/utils/lui/lldbutil.py @@ -1,9 +1,9 @@ ##===-- lldbutil.py ------------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## @@ -14,17 +14,20 @@ They can also be useful for general purpose lldb scripting. """ import lldb -import os, sys +import os +import sys import StringIO # =================================================== # 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) @@ -42,6 +45,7 @@ def which(program): # Disassembly for an SBFunction or an SBSymbol object # =================================================== + def disassemble(target, function_or_symbol): """Disassemble the function or symbol given a target. @@ -57,6 +61,7 @@ def disassemble(target, function_or_symbol): # 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. @@ -82,6 +87,7 @@ def int_to_bytearray(val, bytesize): packed = struct.pack(fmt, val) return bytearray(map(ord, packed)) + def bytearray_to_int(bytes, bytesize): """Utility function to convert a bytearray into an integer. @@ -137,7 +143,7 @@ def get_description(obj, option=None): if not success: return None return stream.GetData() - + # ================================================= # Convert some enum value to its string counterpart @@ -172,6 +178,7 @@ def state_type_to_str(enum): else: raise Exception("Unknown StateType enum") + def stop_reason_to_str(enum): """Returns the stopReason string given an enum.""" if enum == lldb.eStopReasonInvalid: @@ -195,6 +202,7 @@ def stop_reason_to_str(enum): else: raise Exception("Unknown StopReason enum") + def symbol_type_to_str(enum): """Returns the symbolType string given an enum.""" if enum == lldb.eSymbolTypeInvalid: @@ -246,6 +254,7 @@ def symbol_type_to_str(enum): elif enum == lldb.eSymbolTypeUndefined: return "undefined" + def value_type_to_str(enum): """Returns the valueType string given an enum.""" if enum == lldb.eValueTypeInvalid: @@ -273,12 +282,12 @@ def value_type_to_str(enum): # ================================================== def sort_stopped_threads(process, - breakpoint_threads = None, - crashed_threads = None, - watchpoint_threads = None, - signal_threads = None, - exiting_threads = None, - other_threads = None): + 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. """ @@ -307,8 +316,16 @@ def sort_stopped_threads(process, # 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. + +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. @@ -316,10 +333,10 @@ def run_break_set_by_file_and_line (test, file_name, line_number, extra_options 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 == None: - command = 'breakpoint set -l %d'%(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) + command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) if module_name: command += " --shlib '%s'" % (module_name) @@ -327,20 +344,36 @@ def run_break_set_by_file_and_line (test, file_name, line_number, extra_options if extra_options: command += " " + extra_options - break_results = run_break_set_command (test, command) + 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) + 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) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) - 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): +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) + command = 'breakpoint set -n "%s"' % (symbol) if module_name: command += " --shlib '%s'" % (module_name) @@ -348,16 +381,30 @@ def run_break_set_by_symbol (test, symbol, extra_options = None, num_expected_lo if extra_options: command += " " + extra_options - break_results = run_break_set_command (test, command) + 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) + 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) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) - 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): +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) @@ -368,42 +415,68 @@ def run_break_set_by_selector (test, selector, extra_options = None, num_expecte if extra_options: command += " " + extra_options - break_results = run_break_set_command (test, command) + 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) + 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) + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) - return get_bpno_from_match (break_results) + return get_bpno_from_match(break_results) -def run_break_set_by_regexp (test, regexp, extra_options=None, num_expected_locations=-1): + +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) + 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) + 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): + +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) + 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) + 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. + +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. @@ -420,11 +493,12 @@ def run_break_set_command (test, command): 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) + 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 @@ -433,7 +507,7 @@ def run_break_set_command (test, command): 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. @@ -448,61 +522,101 @@ def run_break_set_command (test, command): 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): +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.") + 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)) + 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)) + 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)) + 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: + # 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)) + 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)) + 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)) + + 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. @@ -514,6 +628,7 @@ def get_stopped_threads(process, 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. @@ -542,31 +657,34 @@ def get_stopped_thread(process, reason): return None return threads[0] -def get_threads_stopped_at_breakpoint (process, bkpt): + +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) + 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) + break_id = thread.GetStopReasonDataAtIndex(0) if break_id == bkpt.GetID(): threads.append(thread) return threads -def continue_to_breakpoint (process, bkpt): + +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) + return get_threads_stopped_at_breakpoint(process, bkpt) + def get_caller_symbol(thread): """ @@ -617,7 +735,8 @@ 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 thread.GetFrameAtIndex( + i).GetLineEntry().GetFileSpec().GetFilename() return map(GetFilename, range(thread.GetNumFrames())) @@ -637,7 +756,8 @@ 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 thread.GetFrameAtIndex( + i).GetModule().GetFileSpec().GetFilename() return map(GetModuleName, range(thread.GetNumFrames())) @@ -652,7 +772,7 @@ def get_stack_frames(thread): return map(GetStackFrame, range(thread.GetNumFrames())) -def print_stacktrace(thread, string_buffer = False): +def print_stacktrace(thread, string_buffer=False): """Prints a simple stack trace of this thread.""" output = StringIO.StringIO() if string_buffer else sys.stdout @@ -668,7 +788,7 @@ def print_stacktrace(thread, string_buffer = False): addrs = get_pc_addresses(thread) if thread.GetStopReason() != lldb.eStopReasonInvalid: - desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) + desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) else: desc = "" print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format( @@ -687,16 +807,15 @@ def print_stacktrace(thread, string_buffer = False): num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset) else: print >> output, " 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 '()') + 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 '()') if string_buffer: return output.getvalue() -def print_stacktraces(process, string_buffer = False): +def print_stacktraces(process, string_buffer=False): """Prints the stack traces of all the threads.""" output = StringIO.StringIO() if string_buffer else sys.stdout @@ -713,6 +832,7 @@ def print_stacktraces(process, string_buffer = False): # Utility functions related to Frames # =================================== + def get_parent_frame(frame): """ Returns the parent frame of the input frame object; None if not available. @@ -728,6 +848,7 @@ def get_parent_frame(frame): # 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. @@ -736,8 +857,8 @@ def get_args_as_string(frame, showFuncName=True): # locals => False # statics => False # in_scope_only => True - vars = frame.GetVariables(True, False, False, True) # type of SBValueList - args = [] # list of strings + 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(), @@ -752,37 +873,43 @@ def get_args_as_string(frame, showFuncName=True): return "%s(%s)" % (name, ", ".join(args)) else: return "(%s)" % (", ".join(args)) - -def print_registers(frame, string_buffer = False): + + +def print_registers(frame, string_buffer=False): """Prints all the register sets of the frame.""" output = StringIO.StringIO() if string_buffer else sys.stdout print >> output, "Register sets for " + str(frame) - registerSet = frame.GetRegisters() # Return type of SBValueList. - print >> output, "Frame registers (size of register set = %d):" % registerSet.GetSize() + registerSet = frame.GetRegisters() # Return type of SBValueList. + print >> output, "Frame registers (size of register set = %d):" % registerSet.GetSize( + ) for value in registerSet: - #print >> output, value - print >> output, "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()) + #print >> output, value + print >> output, "%s (number of children = %d):" % ( + value.GetName(), value.GetNumChildren()) for child in value: - print >> output, "Name: %s, Value: %s" % (child.GetName(), child.GetValue()) + print >> output, "Name: %s, Value: %s" % ( + child.GetName(), child.GetValue()) 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. + 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. @@ -796,6 +923,7 @@ def get_GPRs(frame): """ return get_registers(frame, "general purpose") + def get_FPRs(frame): """Returns the floating point registers of the frame as an SBValue. @@ -809,6 +937,7 @@ def get_FPRs(frame): """ return get_registers(frame, "floating point") + def get_ESRs(frame): """Returns the exception state registers of the frame as an SBValue. @@ -826,8 +955,10 @@ def get_ESRs(frame): # 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 = StringIO.StringIO() @@ -836,25 +967,28 @@ class BasicFormatter(object): # If there is a summary, it suffices. val = value.GetSummary() # Otherwise, get the value. - if val == None: + if val is None: val = value.GetValue() - if val == None and value.GetNumChildren() > 0: + if val is None and value.GetNumChildren() > 0: val = "%s (location)" % value.GetLocation() print >> output, "{indentation}({type}) {name} = {value}".format( - indentation = ' ' * indent, - type = value.GetTypeName(), - name = value.GetName(), - value = val) + indentation=' ' * indent, + type=value.GetTypeName(), + name=value.GetName(), + value=val) 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 = StringIO.StringIO() @@ -863,21 +997,25 @@ class ChildVisitingFormatter(BasicFormatter): BasicFormatter.format(self, value, buffer=output) for child in value: - BasicFormatter.format(self, child, buffer=output, indent=self.cindent) + 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. + 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 = StringIO.StringIO() @@ -887,13 +1025,15 @@ class RecursiveDecentFormatter(BasicFormatter): BasicFormatter.format(self, value, buffer=output, indent=self.lindent) new_indent = self.lindent + self.cindent for child in value: - if child.GetSummary() != None: - BasicFormatter.format(self, child, buffer=output, indent=new_indent) + 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) + BasicFormatter.format( + self, child, buffer=output, indent=new_indent) return output.getvalue() diff --git a/utils/lui/lui.py b/utils/lui/lui.py index 31b152c77f0d..9b473f5ff823 100755 --- a/utils/lui/lui.py +++ b/utils/lui/lui.py @@ -1,15 +1,14 @@ #!/usr/bin/env python ##===-- lui.py -----------------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## - import curses import lldb @@ -33,103 +32,119 @@ 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) +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:]) - 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() + 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 __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) + signal.signal(signal.SIGINT, sigint_handler) - global event_queue - event_queue = Queue.Queue() + global event_queue + event_queue = Queue.Queue() - global debugger - debugger = lldb.SBDebugger.Create() + global debugger + debugger = lldb.SBDebugger.Create() - driver = debuggerdriver.createDriver(debugger, event_queue) - view = LLDBUI(screen, event_queue, driver) + driver = debuggerdriver.createDriver(debugger, event_queue) + view = LLDBUI(screen, event_queue, driver) - driver.start() + driver.start() - # hack to avoid hanging waiting for prompts! - driver.handleCommand("settings set auto-confirm true") + # hack to avoid hanging waiting for prompts! + driver.handleCommand("settings set auto-confirm true") - handle_args(driver, sys.argv) - view.eventLoop() + handle_args(driver, sys.argv) + view.eventLoop() if __name__ == "__main__": - try: - curses.wrapper(main) - except KeyboardInterrupt: - exit() + try: + curses.wrapper(main) + except KeyboardInterrupt: + exit() diff --git a/utils/lui/sandbox.py b/utils/lui/sandbox.py index 5a3a64cba692..93b3c23138fa 100755 --- a/utils/lui/sandbox.py +++ b/utils/lui/sandbox.py @@ -1,15 +1,14 @@ #!/usr/bin/env python ##===-- sandbox.py -------------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## - import curses import os @@ -22,52 +21,55 @@ 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 __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() + global event_queue + event_queue = Queue.Queue() - sandbox = SandboxUI(screen, event_queue) - sandbox.eventLoop() + sandbox = SandboxUI(screen, event_queue) + sandbox.eventLoop() if __name__ == "__main__": - try: - curses.wrapper(main) - except KeyboardInterrupt: - exit() + try: + curses.wrapper(main) + except KeyboardInterrupt: + exit() diff --git a/utils/lui/sourcewin.py b/utils/lui/sourcewin.py index 5e7067fdebe2..50d2f2d3e765 100644 --- a/utils/lui/sourcewin.py +++ b/utils/lui/sourcewin.py @@ -1,232 +1,239 @@ ##===-- sourcewin.py -----------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## import cui import curses -import lldb, lldbutil +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() + 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/utils/lui/statuswin.py b/utils/lui/statuswin.py index c6f6c990b34d..3dc34ef1bc8d 100644 --- a/utils/lui/statuswin.py +++ b/utils/lui/statuswin.py @@ -1,40 +1,42 @@ ##===-- statuswin.py -----------------------------------------*- Python -*-===## ## -## The LLVM Compiler Infrastructure +# The LLVM Compiler Infrastructure ## -## This file is distributed under the University of Illinois Open Source -## License. See LICENSE.TXT for details. +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. ## ##===----------------------------------------------------------------------===## -import lldb, lldbutil +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 __init__(self, x, y, w, h): + super(StatusWin, self).__init__(x, y, w) - 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() + self.keys = [ # ('F1', 'Help', curses.KEY_F1), + ('F3', 'Cycle-focus', curses.KEY_F3), + ('F10', 'Quit', curses.KEY_F10)] - 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 + 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 diff --git a/utils/misc/grep-svn-log.py b/utils/misc/grep-svn-log.py index ebbfe33f0520..86cc3ef1742f 100755 --- a/utils/misc/grep-svn-log.py +++ b/utils/misc/grep-svn-log.py @@ -9,7 +9,10 @@ Example: svn log -v | grep-svn-log.py '^ D.+why_are_you_missing.h$' """ -import fileinput, re, sys, StringIO +import fileinput +import re +import sys +import StringIO # Separator string for "svn log -v" output. separator = '-' * 72 @@ -18,30 +21,37 @@ usage = """Usage: grep-svn-log.py line-pattern Example: svn log -v | grep-svn-log.py '^ D.+why_are_you_missing.h'""" + class Log(StringIO.StringIO): """Simple facade to keep track of the log content.""" + def __init__(self): self.reset() + def add_line(self, a_line): """Add a line to the content, if there is a previous line, commit it.""" global separator - if self.prev_line != None: + if self.prev_line is not None: print >> self, self.prev_line self.prev_line = a_line self.separator_added = (a_line == separator) + def del_line(self): """Forget about the previous line, do not commit it.""" self.prev_line = None + def reset(self): """Forget about the previous lines entered.""" StringIO.StringIO.__init__(self) self.prev_line = None + def finish(self): """Call this when you're finished with populating content.""" - if self.prev_line != None: + if self.prev_line is not None: print >> self, self.prev_line self.prev_line = None + def grep(regexp): # The log content to be written out once a match is found. log = Log() @@ -50,7 +60,7 @@ def grep(regexp): FOUND_LINE_MATCH = 1 state = LOOKING_FOR_MATCH - while 1: + while True: line = sys.stdin.readline() if not line: return @@ -72,6 +82,7 @@ def grep(regexp): if regexp.search(line): state = FOUND_LINE_MATCH + def main(): if len(sys.argv) != 2: print usage diff --git a/utils/sync-source/lib/transfer/protocol.py b/utils/sync-source/lib/transfer/protocol.py index 6a4e6e0a3a45..0f89db7d87ef 100644 --- a/utils/sync-source/lib/transfer/protocol.py +++ b/utils/sync-source/lib/transfer/protocol.py @@ -1,4 +1,5 @@ class Protocol(object): + def __init__(self, options, config): self.options = options self.config = config diff --git a/utils/sync-source/lib/transfer/rsync.py b/utils/sync-source/lib/transfer/rsync.py index 7a89344b6991..8269fada676a 100644 --- a/utils/sync-source/lib/transfer/rsync.py +++ b/utils/sync-source/lib/transfer/rsync.py @@ -7,6 +7,7 @@ import transfer.protocol class RsyncOverSsh(transfer.protocol.Protocol): + def __init__(self, options, config): super(RsyncOverSsh, self).__init__(options, config) self.ssh_config = config.get_value("ssh") diff --git a/utils/sync-source/lib/transfer/transfer_spec.py b/utils/sync-source/lib/transfer/transfer_spec.py index cc76c70bf41c..12da8b64aa2a 100644 --- a/utils/sync-source/lib/transfer/transfer_spec.py +++ b/utils/sync-source/lib/transfer/transfer_spec.py @@ -1,4 +1,5 @@ class TransferSpec(object): + def __init__(self, source_path, exclude_paths, dest_path): self.source_path = source_path self.exclude_paths = exclude_paths diff --git a/utils/sync-source/syncsource.py b/utils/sync-source/syncsource.py index 736aefd9a35c..9e27ca2b702e 100644 --- a/utils/sync-source/syncsource.py +++ b/utils/sync-source/syncsource.py @@ -33,6 +33,7 @@ DOTRC_BASE_FILENAME = ".syncsourcerc" class Configuration(object): """Provides chaining configuration lookup.""" + def __init__(self, rcdata_configs): self.__rcdata_configs = rcdata_configs diff --git a/utils/test/disasm.py b/utils/test/disasm.py index 46660299f188..e75c070e0117 100755 --- a/utils/test/disasm.py +++ b/utils/test/disasm.py @@ -10,10 +10,12 @@ import os import sys from optparse import OptionParser + def is_exe(fpath): """Check whether fpath is an executable.""" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + def which(program): """Find the full path to a program, or return None.""" fpath, fname = os.path.split(program) @@ -27,8 +29,15 @@ def which(program): return exe_file return None -def do_llvm_mc_disassembly(gdb_commands, gdb_options, exe, func, mc, mc_options): - from cStringIO import StringIO + +def do_llvm_mc_disassembly( + gdb_commands, + gdb_options, + exe, + func, + mc, + mc_options): + from cStringIO import StringIO import pexpect gdb_prompt = "\r\n\(gdb\) " @@ -37,7 +46,8 @@ def do_llvm_mc_disassembly(gdb_commands, gdb_options, exe, func, mc, mc_options) gdb.logfile_read = sys.stdout gdb.expect(gdb_prompt) - # See if there any extra command(s) to execute before we issue the file command. + # See if there any extra command(s) to execute before we issue the file + # command. for cmd in gdb_commands: gdb.sendline(cmd) gdb.expect(gdb_prompt) @@ -93,12 +103,14 @@ def do_llvm_mc_disassembly(gdb_commands, gdb_options, exe, func, mc, mc_options) # Get the last output line from the gdb examine memory command, # split the string into a 3-tuple with separator '>:' to handle # objc method names. - memory_dump = x_output.split(os.linesep)[-1].partition('>:')[2].strip() - #print "\nbytes:", memory_dump + memory_dump = x_output.split( + os.linesep)[-1].partition('>:')[2].strip() + # print "\nbytes:", memory_dump disasm_str = prev_line.partition('>:')[2] print >> mc_input, '%s # %s' % (memory_dump, disasm_str) - # We're done with the processing. Assign the current line to be prev_line. + # We're done with the processing. Assign the current line to be + # prev_line. prev_line = line # Close the gdb session now that we are done with it. @@ -117,15 +129,21 @@ def do_llvm_mc_disassembly(gdb_commands, gdb_options, exe, func, mc, mc_options) # And invoke llvm-mc with the just recorded file. #mc = pexpect.spawn('%s -disassemble %s disasm-input.txt' % (mc, mc_options)) #mc.logfile_read = sys.stdout - #print "mc:", mc - #mc.close() - + # print "mc:", mc + # mc.close() + def main(): # This is to set up the Python path to include the pexpect-2.4 dir. # Remember to update this when/if things change. scriptPath = sys.path[0] - sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4')) + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) parser = OptionParser(usage="""\ Run gdb to disassemble a function, feed the bytes to 'llvm-mc -disassemble' command, @@ -133,32 +151,46 @@ and display the disassembly result. Usage: %prog [options] """) - parser.add_option('-C', '--gdb-command', - type='string', action='append', metavar='COMMAND', - default=[], dest='gdb_commands', - help='Command(s) gdb executes after starting up (can be empty)') - parser.add_option('-O', '--gdb-options', - type='string', action='store', - dest='gdb_options', - help="""The options passed to 'gdb' command if specified.""") + parser.add_option( + '-C', + '--gdb-command', + type='string', + action='append', + metavar='COMMAND', + default=[], + dest='gdb_commands', + help='Command(s) gdb executes after starting up (can be empty)') + parser.add_option( + '-O', + '--gdb-options', + type='string', + action='store', + dest='gdb_options', + help="""The options passed to 'gdb' command if specified.""") parser.add_option('-e', '--executable', type='string', action='store', dest='executable', help="""The executable to do disassembly on.""") - parser.add_option('-f', '--function', - type='string', action='store', - dest='function', - help="""The function name (could be an address to gdb) for disassembly.""") + parser.add_option( + '-f', + '--function', + type='string', + action='store', + dest='function', + help="""The function name (could be an address to gdb) for disassembly.""") parser.add_option('-m', '--llvm-mc', type='string', action='store', dest='llvm_mc', help="""The llvm-mc executable full path, if specified. Otherwise, it must be present in your PATH environment.""") - parser.add_option('-o', '--options', - type='string', action='store', - dest='llvm_mc_options', - help="""The options passed to 'llvm-mc -disassemble' command if specified.""") + parser.add_option( + '-o', + '--options', + type='string', + action='store', + dest='llvm_mc_options', + help="""The options passed to 'llvm-mc -disassemble' command if specified.""") opts, args = parser.parse_args() @@ -192,7 +224,13 @@ Usage: %prog [options] print "llvm-mc:", llvm_mc print "llvm-mc options:", llvm_mc_options - do_llvm_mc_disassembly(gdb_commands, gdb_options, executable, function, llvm_mc, llvm_mc_options) + do_llvm_mc_disassembly( + gdb_commands, + gdb_options, + executable, + function, + llvm_mc, + llvm_mc_options) if __name__ == '__main__': main() diff --git a/utils/test/lldb-disasm.py b/utils/test/lldb-disasm.py index 7987c6b01c37..1069bf477af2 100755 --- a/utils/test/lldb-disasm.py +++ b/utils/test/lldb-disasm.py @@ -10,6 +10,7 @@ import re import sys from optparse import OptionParser + def setupSysPath(): """ Add LLDB.framework/Resources/Python and the test dir to the sys.path. @@ -24,7 +25,7 @@ def setupSysPath(): base = os.path.abspath(os.path.join(scriptPath, os.pardir, os.pardir)) # This is for the goodies in the test directory under base. - sys.path.append(os.path.join(base,'test')) + sys.path.append(os.path.join(base, 'test')) # These are for xcode build directories. xcode3_build_dir = ['build'] @@ -34,12 +35,18 @@ def setupSysPath(): bai = ['BuildAndIntegration'] python_resource_dir = ['LLDB.framework', 'Resources', 'Python'] - dbgPath = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir)) - dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir)) - relPath = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir)) - relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir)) - baiPath = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir)) - baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir)) + dbgPath = os.path.join( + base, *(xcode3_build_dir + dbg + python_resource_dir)) + dbgPath2 = os.path.join( + base, *(xcode4_build_dir + dbg + python_resource_dir)) + relPath = os.path.join( + base, *(xcode3_build_dir + rel + python_resource_dir)) + relPath2 = os.path.join( + base, *(xcode4_build_dir + rel + python_resource_dir)) + baiPath = os.path.join( + base, *(xcode3_build_dir + bai + python_resource_dir)) + baiPath2 = os.path.join( + base, *(xcode4_build_dir + bai + python_resource_dir)) lldbPath = None if os.path.isfile(os.path.join(dbgPath, 'lldb.py')): @@ -62,7 +69,7 @@ def setupSysPath(): # This is to locate the lldb.py module. Insert it right after sys.path[0]. sys.path[1:1] = [lldbPath] - #print "sys.path:", sys.path + # print "sys.path:", sys.path def run_command(ci, cmd, res, echo=True): @@ -77,16 +84,19 @@ def run_command(ci, cmd, res, echo=True): print "run command failed!" print "run_command error:", res.GetError() + def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, symbols_to_disassemble, re_symbol_pattern, quiet_disassembly): - import lldb, atexit, re + import lldb + import atexit + import re # Create the debugger instance now. dbg = lldb.SBDebugger.Create() if not dbg: - raise Exception('Invalid debugger instance') + raise Exception('Invalid debugger instance') # Register an exit callback. atexit.register(lambda: lldb.SBDebugger.Terminate()) @@ -102,7 +112,8 @@ def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, # And the associated result object. res = lldb.SBCommandReturnObject() - # See if there any extra command(s) to execute before we issue the file command. + # See if there any extra command(s) to execute before we issue the file + # command. for cmd in lldb_commands: run_command(ci, cmd, res, not quiet_disassembly) @@ -141,7 +152,8 @@ def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, return # If a regexp symbol pattern is supplied, consult it. if re_symbol_pattern: - # If the pattern does not match, look for the next symbol. + # If the pattern does not match, look for the next + # symbol. if not pattern.match(s.GetName()): continue @@ -162,7 +174,12 @@ def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, stream.Clear() # Disassembly time. - for symbol in symbol_iter(num_symbols, symbols_to_disassemble, re_symbol_pattern, target, not quiet_disassembly): + for symbol in symbol_iter( + num_symbols, + symbols_to_disassemble, + re_symbol_pattern, + target, + not quiet_disassembly): cmd = "disassemble %s '%s'" % (disassemble_options, symbol) run_command(ci, cmd, res, not quiet_disassembly) @@ -171,42 +188,74 @@ def main(): # This is to set up the Python path to include the pexpect-2.4 dir. # Remember to update this when/if things change. scriptPath = sys.path[0] - sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4')) + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) parser = OptionParser(usage="""\ Run lldb to disassemble all the available functions for an executable image. Usage: %prog [options] """) - parser.add_option('-C', '--lldb-command', - type='string', action='append', metavar='COMMAND', - default=[], dest='lldb_commands', - help='Command(s) lldb executes after starting up (can be empty)') - parser.add_option('-e', '--executable', - type='string', action='store', - dest='executable', - help="""Mandatory: the executable to do disassembly on.""") - parser.add_option('-o', '--options', - type='string', action='store', - dest='disassemble_options', - help="""Mandatory: the options passed to lldb's 'disassemble' command.""") - parser.add_option('-q', '--quiet-disassembly', - action='store_true', default=False, - dest='quiet_disassembly', - help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") - parser.add_option('-n', '--num-symbols', - type='int', action='store', default=-1, - dest='num_symbols', - help="""The number of symbols to disassemble, if specified.""") - parser.add_option('-p', '--symbol_pattern', - type='string', action='store', - dest='re_symbol_pattern', - help="""The regular expression of symbols to invoke lldb's 'disassemble' command.""") - parser.add_option('-s', '--symbol', - type='string', action='append', metavar='SYMBOL', default=[], - dest='symbols_to_disassemble', - help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") - + parser.add_option( + '-C', + '--lldb-command', + type='string', + action='append', + metavar='COMMAND', + default=[], + dest='lldb_commands', + help='Command(s) lldb executes after starting up (can be empty)') + parser.add_option( + '-e', + '--executable', + type='string', + action='store', + dest='executable', + help="""Mandatory: the executable to do disassembly on.""") + parser.add_option( + '-o', + '--options', + type='string', + action='store', + dest='disassemble_options', + help="""Mandatory: the options passed to lldb's 'disassemble' command.""") + parser.add_option( + '-q', + '--quiet-disassembly', + action='store_true', + default=False, + dest='quiet_disassembly', + help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") + parser.add_option( + '-n', + '--num-symbols', + type='int', + action='store', + default=-1, + dest='num_symbols', + help="""The number of symbols to disassemble, if specified.""") + parser.add_option( + '-p', + '--symbol_pattern', + type='string', + action='store', + dest='re_symbol_pattern', + help="""The regular expression of symbols to invoke lldb's 'disassemble' command.""") + parser.add_option( + '-s', + '--symbol', + type='string', + action='append', + metavar='SYMBOL', + default=[], + dest='symbols_to_disassemble', + help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") + opts, args = parser.parse_args() lldb_commands = opts.lldb_commands diff --git a/utils/test/llvm-mc-shell.py b/utils/test/llvm-mc-shell.py index 38c12992b914..4d3119598423 100755 --- a/utils/test/llvm-mc-shell.py +++ b/utils/test/llvm-mc-shell.py @@ -9,10 +9,12 @@ import os import sys from optparse import OptionParser + def is_exe(fpath): """Check whether fpath is an executable.""" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + def which(program): """Find the full path to a program, or return None.""" fpath, fname = os.path.split(program) @@ -26,10 +28,12 @@ def which(program): return exe_file return None + def llvm_mc_loop(mc, mc_options): contents = [] fname = 'mc-input.txt' - sys.stdout.write("Enter your input to llvm-mc. A line starting with 'END' terminates the current batch of input.\n") + sys.stdout.write( + "Enter your input to llvm-mc. A line starting with 'END' terminates the current batch of input.\n") sys.stdout.write("Enter 'quit' or Ctrl-D to quit the program.\n") while True: sys.stdout.write("> ") @@ -54,11 +58,18 @@ def llvm_mc_loop(mc, mc_options): # Keep accumulating our input. contents.append(next) + def main(): # This is to set up the Python path to include the pexpect-2.4 dir. # Remember to update this when/if things change. scriptPath = sys.path[0] - sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4')) + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) parser = OptionParser(usage="""\ Do llvm-mc interactively within a shell-like environment. A batch of input is @@ -74,10 +85,13 @@ Usage: %prog [options] help="""The llvm-mc executable full path, if specified. Otherwise, it must be present in your PATH environment.""") - parser.add_option('-o', '--options', - type='string', action='store', - dest='llvm_mc_options', - help="""The options passed to 'llvm-mc' command if specified.""") + parser.add_option( + '-o', + '--options', + type='string', + action='store', + dest='llvm_mc_options', + help="""The options passed to 'llvm-mc' command if specified.""") opts, args = parser.parse_args() diff --git a/utils/test/main.c b/utils/test/main.c index c0fe2f25a488..c0f600995d26 100644 --- a/utils/test/main.c +++ b/utils/test/main.c @@ -1,14 +1,13 @@ #include <stdio.h> #include <stdlib.h> -int main(int argc, const char* argv[]) -{ - int *null_ptr = 0; - printf("Hello, fault!\n"); - u_int32_t val = (arc4random() & 0x0f); - printf("val=%u\n", val); - if (val == 0x07) // Lucky 7 :-) - printf("Now segfault %d\n", *null_ptr); - else - printf("Better luck next time!\n"); +int main(int argc, const char *argv[]) { + int *null_ptr = 0; + printf("Hello, fault!\n"); + u_int32_t val = (arc4random() & 0x0f); + printf("val=%u\n", val); + if (val == 0x07) // Lucky 7 :-) + printf("Now segfault %d\n", *null_ptr); + else + printf("Better luck next time!\n"); } diff --git a/utils/test/ras.py b/utils/test/ras.py index a89cbae8c88d..25b76bc1e072 100755 --- a/utils/test/ras.py +++ b/utils/test/ras.py @@ -24,7 +24,8 @@ from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -def runTestsuite(testDir, sessDir, envs = None): + +def runTestsuite(testDir, sessDir, envs=None): """Run the testsuite and return a (summary, output) tuple.""" os.chdir(testDir) @@ -35,7 +36,8 @@ def runTestsuite(testDir, sessDir, envs = None): print var + "=" + val os.environ[var] = val - import shlex, subprocess + import shlex + import subprocess command_line = "./dotest.py -w -s %s" % sessDir # Apply correct tokenization for subprocess.Popen(). @@ -46,7 +48,7 @@ def runTestsuite(testDir, sessDir, envs = None): stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Wait for subprocess to terminate. stdout, stderr = process.communicate() - + # This will be used as the subject line of our email about this test. cmd = "%s %s" % (' '.join(envs) if envs else "", command_line) @@ -55,6 +57,7 @@ def runTestsuite(testDir, sessDir, envs = None): COMMASPACE = ', ' + def main(): parser = OptionParser(usage="""\ Run lldb test suite and send the results as a MIME message. @@ -103,7 +106,7 @@ SMTP server, which then does the normal delivery process. sessDir = 'tmp-lldb-session' if os.path.exists(sessDir): shutil.rmtree(sessDir) - #print "environments:", opts.environments + # print "environments:", opts.environments summary, output = runTestsuite(testDir, sessDir, opts.environments) # Create the enclosing (outer) message @@ -119,9 +122,10 @@ SMTP server, which then does the normal delivery process. if not os.path.exists(sessDir): outer.attach(MIMEText(output, 'plain')) else: - outer.attach(MIMEText("%s\n%s\n\n" % (output, - "Session logs of test failures/errors:"), - 'plain')) + outer.attach( + MIMEText( + "%s\n%s\n\n" % + (output, "Session logs of test failures/errors:"), 'plain')) for filename in (os.listdir(sessDir) if os.path.exists(sessDir) else []): path = os.path.join(sessDir, filename) diff --git a/utils/test/run-dis.py b/utils/test/run-dis.py index a2437948e47d..b635e8c62d8c 100755 --- a/utils/test/run-dis.py +++ b/utils/test/run-dis.py @@ -5,7 +5,9 @@ Run lldb disassembler on all the binaries specified by a combination of root dir and path pattern. """ -import os, sys, subprocess +import os +import sys +import subprocess import re from optparse import OptionParser @@ -29,11 +31,14 @@ template = '%s/lldb-disasm.py -C "platform select remote-ios" -o "-n" -q -e %s - # Regular expression for detecting file output for Mach-o binary. mach_o = re.compile('\sMach-O.+binary') + + def isbinary(path): - file_output = subprocess.Popen(["file", path], + file_output = subprocess.Popen(["file", path], stdout=subprocess.PIPE).stdout.read() return (mach_o.search(file_output) is not None) + def walk_and_invoke(sdk_root, path_regexp, suffix, num_symbols): """Look for matched file and invoke lldb disassembly on it.""" global scriptPath @@ -49,7 +54,8 @@ def walk_and_invoke(sdk_root, path_regexp, suffix, num_symbols): if os.path.islink(path): continue - # We'll be pattern matching based on the path relative to the SDK root. + # We'll be pattern matching based on the path relative to the SDK + # root. replaced_path = path.replace(root_dir, "", 1) # Check regular expression match for the replaced path. if not path_regexp.search(replaced_path): @@ -60,10 +66,12 @@ def walk_and_invoke(sdk_root, path_regexp, suffix, num_symbols): if not isbinary(path): continue - command = template % (scriptPath, path, num_symbols if num_symbols > 0 else 1000) + command = template % ( + scriptPath, path, num_symbols if num_symbols > 0 else 1000) print "Running %s" % (command) os.system(command) + def main(): """Read the root dir and the path spec, invoke lldb-disasm.py on the file.""" global scriptPath @@ -78,23 +86,32 @@ def main(): Run lldb disassembler on all the binaries specified by a combination of root dir and path pattern. """) - parser.add_option('-r', '--root-dir', - type='string', action='store', - dest='root_dir', - help='Mandatory: the root directory for the SDK symbols.') - parser.add_option('-p', '--path-pattern', - type='string', action='store', - dest='path_pattern', - help='Mandatory: regular expression pattern for the desired binaries.') + parser.add_option( + '-r', + '--root-dir', + type='string', + action='store', + dest='root_dir', + help='Mandatory: the root directory for the SDK symbols.') + parser.add_option( + '-p', + '--path-pattern', + type='string', + action='store', + dest='path_pattern', + help='Mandatory: regular expression pattern for the desired binaries.') parser.add_option('-s', '--suffix', type='string', action='store', default=None, dest='suffix', help='Specify the suffix of the binaries to look for.') - parser.add_option('-n', '--num-symbols', - type='int', action='store', default=-1, - dest='num_symbols', - help="""The number of symbols to disassemble, if specified.""") - + parser.add_option( + '-n', + '--num-symbols', + type='int', + action='store', + default=-1, + dest='num_symbols', + help="""The number of symbols to disassemble, if specified.""") opts, args = parser.parse_args() if not opts.root_dir or not opts.path_pattern: diff --git a/utils/test/run-until-faulted.py b/utils/test/run-until-faulted.py index d895f565a79e..794f4fc84786 100755 --- a/utils/test/run-until-faulted.py +++ b/utils/test/run-until-faulted.py @@ -9,10 +9,12 @@ import os import sys from optparse import OptionParser + def is_exe(fpath): """Check whether fpath is an executable.""" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + def which(program): """Find the full path to a program, or return None.""" fpath, fname = os.path.split(program) @@ -26,9 +28,11 @@ def which(program): return exe_file return None + def do_lldb_launch_loop(lldb_command, exe, exe_options): - from cStringIO import StringIO - import pexpect, time + from cStringIO import StringIO + import pexpect + import time prompt = "\(lldb\) " lldb = pexpect.spawn(lldb_command) @@ -37,17 +41,18 @@ def do_lldb_launch_loop(lldb_command, exe, exe_options): lldb.expect(prompt) # Now issue the file command. - #print "sending 'file %s' command..." % exe + # print "sending 'file %s' command..." % exe lldb.sendline('file %s' % exe) lldb.expect(prompt) # Loop until it faults.... count = 0 - #while True: + # while True: # count = count + 1 for i in range(100): count = i - #print "sending 'process launch -- %s' command... (iteration: %d)" % (exe_options, count) + # print "sending 'process launch -- %s' command... (iteration: %d)" % + # (exe_options, count) lldb.sendline('process launch -- %s' % exe_options) index = lldb.expect(['Process .* exited with status', 'Process .* stopped', @@ -57,19 +62,26 @@ def do_lldb_launch_loop(lldb_command, exe, exe_options): time.sleep(3) elif index == 1: # Perfect, our process had stopped; break out of the loop. - break; + break elif index == 2: # Something went wrong. - print "TIMEOUT occurred:", str(lldb) + print "TIMEOUT occurred:", str(lldb) # Give control of lldb shell to the user. lldb.interact() + def main(): # This is to set up the Python path to include the pexpect-2.4 dir. # Remember to update this when/if things change. scriptPath = sys.path[0] - sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4')) + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) parser = OptionParser(usage="""\ %prog [options] @@ -80,14 +92,21 @@ The lldb executable is located via your PATH env variable, if not specified.\ type='string', action='store', metavar='LLDB_COMMAND', default='lldb', dest='lldb_command', help='Full path to your lldb command') - parser.add_option('-e', '--executable', - type='string', action='store', - dest='exe', - help="""(Mandatory) The executable to launch via lldb.""") - parser.add_option('-o', '--options', - type='string', action='store', - default = '', dest='exe_options', - help="""The args/options passed to the launched program, if specified.""") + parser.add_option( + '-e', + '--executable', + type='string', + action='store', + dest='exe', + help="""(Mandatory) The executable to launch via lldb.""") + parser.add_option( + '-o', + '--options', + type='string', + action='store', + default='', + dest='exe_options', + help="""The args/options passed to the launched program, if specified.""") opts, args = parser.parse_args() diff --git a/utils/vim-lldb/python-vim-lldb/import_lldb.py b/utils/vim-lldb/python-vim-lldb/import_lldb.py index a2145d504661..41cb42b1bb38 100644 --- a/utils/vim-lldb/python-vim-lldb/import_lldb.py +++ b/utils/vim-lldb/python-vim-lldb/import_lldb.py @@ -1,61 +1,71 @@ # Locate and load the lldb python module -import os, sys +import os +import sys + def import_lldb(): - """ Find and import the lldb modules. This function tries to find the lldb module by: - 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, - 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb - on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid - path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the - default Xcode 4.5 installation path. - """ - - # Try simple 'import lldb', in case of a system-wide install or a pre-configured PYTHONPATH - try: - import lldb - return True - except ImportError: - pass - - # Allow overriding default path to lldb executable with the LLDB environment variable - lldb_executable = 'lldb' - if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): - lldb_executable = os.environ['LLDB'] - - # Try using builtin module location support ('lldb -P') - from subprocess import check_output, CalledProcessError - try: - with open(os.devnull, 'w') as fnull: - lldb_minus_p_path = check_output("%s -P" % lldb_executable, shell=True, stderr=fnull).strip() - if not os.path.exists(lldb_minus_p_path): - #lldb -P returned invalid path, probably too old - pass - else: - sys.path.append(lldb_minus_p_path) - import lldb - return True - except CalledProcessError: - # Cannot run 'lldb -P' to determine location of lldb python module - pass - except ImportError: - # Unable to import lldb module from path returned by `lldb -P` - pass - - # On Mac OS X, use the try the default path to XCode lldb module - if "darwin" in sys.platform: - xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" - sys.path.append(xcode_python_path) + """ Find and import the lldb modules. This function tries to find the lldb module by: + 1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails, + 2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb + on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid + path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the + default Xcode 4.5 installation path. + """ + + # Try simple 'import lldb', in case of a system-wide install or a + # pre-configured PYTHONPATH try: - import lldb - return True + import lldb + return True except ImportError: - # Unable to import lldb module from default Xcode python path - pass + pass + + # Allow overriding default path to lldb executable with the LLDB + # environment variable + lldb_executable = 'lldb' + if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']): + lldb_executable = os.environ['LLDB'] + + # Try using builtin module location support ('lldb -P') + from subprocess import check_output, CalledProcessError + try: + with open(os.devnull, 'w') as fnull: + lldb_minus_p_path = check_output( + "%s -P" % + lldb_executable, + shell=True, + stderr=fnull).strip() + if not os.path.exists(lldb_minus_p_path): + # lldb -P returned invalid path, probably too old + pass + else: + sys.path.append(lldb_minus_p_path) + import lldb + return True + except CalledProcessError: + # Cannot run 'lldb -P' to determine location of lldb python module + pass + except ImportError: + # Unable to import lldb module from path returned by `lldb -P` + pass + + # On Mac OS X, use the try the default path to XCode lldb module + if "darwin" in sys.platform: + xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/" + sys.path.append(xcode_python_path) + try: + import lldb + return True + except ImportError: + # Unable to import lldb module from default Xcode python path + pass - return False + return False if not import_lldb(): - import vim - vim.command('redraw | echo "%s"' % " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") + import vim + vim.command( + 'redraw | echo "%s"' % + " Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.") diff --git a/utils/vim-lldb/python-vim-lldb/lldb_controller.py b/utils/vim-lldb/python-vim-lldb/lldb_controller.py index 923e771e6afe..ed54633a3ea2 100644 --- a/utils/vim-lldb/python-vim-lldb/lldb_controller.py +++ b/utils/vim-lldb/python-vim-lldb/lldb_controller.py @@ -3,7 +3,9 @@ # This file defines the layer that talks to lldb # -import os, re, sys +import os +import re +import sys import lldb import vim from vim_ui import UI @@ -13,372 +15,399 @@ from vim_ui import UI # ================================================= # Shamelessly copy/pasted from lldbutil.py in the test suite -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") -class StepType: - INSTRUCTION = 1 - INSTRUCTION_OVER = 2 - INTO = 3 - OVER = 4 - OUT = 5 -class LLDBController(object): - """ Handles Vim and LLDB events such as commands and lldb events. """ - - # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to - # servicing LLDB events from the main UI thread. Usually, we only process events that are already - # sitting on the queue. But in some situations (when we are expecting an event as a result of some - # user interaction) we want to wait for it. The constants below set these wait period in which the - # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher - # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at - # times. - eventDelayStep = 2 - eventDelayLaunch = 1 - eventDelayContinue = 1 - - def __init__(self): - """ Creates the LLDB SBDebugger object and initializes the UI class. """ - self.target = None - self.process = None - self.load_dependent_modules = True - - self.dbg = lldb.SBDebugger.Create() - self.commandInterpreter = self.dbg.GetCommandInterpreter() - - self.ui = UI() - - def completeCommand(self, a, l, p): - """ Returns a list of viable completions for command a with length l and cursor at p """ - - assert l[0] == 'L' - # Remove first 'L' character that all commands start with - l = l[1:] - - # Adjust length as string has 1 less character - p = int(p) - 1 - - result = lldb.SBStringList() - num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) - - if num == -1: - # FIXME: insert completion character... what's a completion character? - pass - elif num == -2: - # FIXME: replace line with result.GetStringAtIndex(0) - pass - - if result.GetSize() > 0: - results = filter(None, [result.GetStringAtIndex(x) for x in range(result.GetSize())]) - return results - else: - return [] - - def doStep(self, stepType): - """ Perform a step command and block the UI for eventDelayStep seconds in order to process - events on lldb's event queue. - FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to - the main thread to avoid the appearance of a "hang". If this happens, the UI will - update whenever; usually when the user moves the cursor. This is somewhat annoying. - """ - if not self.process: - sys.stderr.write("No process to step") - return - - t = self.process.GetSelectedThread() - if stepType == StepType.INSTRUCTION: - t.StepInstruction(False) - if stepType == StepType.INSTRUCTION_OVER: - t.StepInstruction(True) - elif stepType == StepType.INTO: - t.StepInto() - elif stepType == StepType.OVER: - t.StepOver() - elif stepType == StepType.OUT: - t.StepOut() - - self.processPendingEvents(self.eventDelayStep, True) - - def doSelect(self, command, args): - """ Like doCommand, but suppress output when "select" is the first argument.""" - a = args.split(' ') - return self.doCommand(command, args, "select" != a[0], True) - - def doProcess(self, args): - """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead - of the command interpreter to start the inferior process. - """ - a = args.split(' ') - if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): - self.doCommand("process", args) - #self.ui.update(self.target, "", self) - else: - self.doLaunch('-s' not in args, "") - - def doAttach(self, process_name): - """ Handle process attach. """ - error = lldb.SBError() - - self.processListener = lldb.SBListener("process_event_listener") - self.target = self.dbg.CreateTarget('') - self.process = self.target.AttachToProcessWithName(self.processListener, process_name, False, error) - if not error.Success(): - sys.stderr.write("Error during attach: " + str(error)) - return - - self.ui.activate() - self.pid = self.process.GetProcessID() - - print "Attached to %s (pid=%d)" % (process_name, self.pid) - - def doDetach(self): - if self.process is not None and self.process.IsValid(): - pid = self.process.GetProcessID() - state = state_type_to_str(self.process.GetState()) - self.process.Detach() - self.processPendingEvents(self.eventDelayLaunch) - - def doLaunch(self, stop_at_entry, args): - """ Handle process launch. """ - error = lldb.SBError() - - fs = self.target.GetExecutable() - exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) - if self.process is not None and self.process.IsValid(): - pid = self.process.GetProcessID() - state = state_type_to_str(self.process.GetState()) - self.process.Destroy() - - launchInfo = lldb.SBLaunchInfo(args.split(' ')) - self.process = self.target.Launch(launchInfo, error) - if not error.Success(): - sys.stderr.write("Error during launch: " + str(error)) - return - - # launch succeeded, store pid and add some event listeners - self.pid = self.process.GetProcessID() - self.processListener = lldb.SBListener("process_event_listener") - self.process.GetBroadcaster().AddListener(self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) - - print "Launched %s %s (pid=%d)" % (exe, args, self.pid) - - if not stop_at_entry: - self.doContinue() +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: - self.processPendingEvents(self.eventDelayLaunch) - - def doTarget(self, args): - """ Pass target command to interpreter, except if argument is not one of the valid options, or - is create, in which case try to create a target with the argument as the executable. For example: - target list ==> handled by interpreter - target create blah ==> custom creation of target 'blah' - target blah ==> also creates target blah - """ - target_args = [#"create", - "delete", - "list", - "modules", - "select", - "stop-hook", - "symbols", - "variable"] - - a = args.split(' ') - if len(args) == 0 or (len(a) > 0 and a[0] in target_args): - self.doCommand("target", args) - return - elif len(a) > 1 and a[0] == "create": - exe = a[1] - elif len(a) == 1 and a[0] not in target_args: - exe = a[0] - - err = lldb.SBError() - self.target = self.dbg.CreateTarget(exe, None, None, self.load_dependent_modules, err) - if not self.target: - sys.stderr.write("Error creating target %s. %s" % (str(exe), str(err))) - return - - self.ui.activate() - self.ui.update(self.target, "created target %s" % str(exe), self) - - def doContinue(self): - """ Handle 'contiue' command. - FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. - """ - if not self.process or not self.process.IsValid(): - sys.stderr.write("No process to continue") - return + raise Exception("Unknown StateType enum") - self.process.Continue() - self.processPendingEvents(self.eventDelayContinue) - def doBreakpoint(self, args): - """ Handle breakpoint command with command interpreter, except if the user calls - "breakpoint" with no other args, in which case add a breakpoint at the line - under the cursor. - """ - a = args.split(' ') - if len(args) == 0: - show_output = False - - # User called us with no args, so toggle the bp under cursor - cw = vim.current.window - cb = vim.current.buffer - name = cb.name - line = cw.cursor[0] - - # Since the UI is responsbile for placing signs at bp locations, we have to - # ask it if there already is one or more breakpoints at (file, line)... - if self.ui.haveBreakpoint(name, line): - bps = self.ui.getBreakpoints(name, line) - args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) - self.ui.deleteBreakpoints(name, line) - else: - args = "set -f %s -l %d" % (name, line) - else: - show_output = True - - self.doCommand("breakpoint", args, show_output) - return - - def doRefresh(self): - """ process pending events and update UI on request """ - status = self.processPendingEvents() - - def doShow(self, name): - """ handle :Lshow <name> """ - if not name: - self.ui.activate() - return - - if self.ui.showWindow(name): - self.ui.update(self.target, "", self) - - def doHide(self, name): - """ handle :Lhide <name> """ - if self.ui.hideWindow(name): - self.ui.update(self.target, "", self) - - def doExit(self): - self.dbg.Terminate() - self.dbg = None - - def getCommandResult(self, command, command_args): - """ Run cmd in the command interpreter and returns (success, output) """ - result = lldb.SBCommandReturnObject() - cmd = "%s %s" % (command, command_args) - - self.commandInterpreter.HandleCommand(cmd, result) - return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) - - def doCommand(self, command, command_args, print_on_success = True, goto_file=False): - """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ - (success, output) = self.getCommandResult(command, command_args) - if success: - self.ui.update(self.target, "", self, goto_file) - if len(output) > 0 and print_on_success: - print output - else: - sys.stderr.write(output) - - def getCommandOutput(self, command, command_args=""): - """ runs cmd in the command interpreter andreturns (status, result) """ - result = lldb.SBCommandReturnObject() - cmd = "%s %s" % (command, command_args) - self.commandInterpreter.HandleCommand(cmd, result) - return (result.Succeeded(), result.GetOutput() if result.Succeeded() else result.GetError()) - - def processPendingEvents(self, wait_seconds=0, goto_file=True): - """ Handle any events that are queued from the inferior. - Blocks for at most wait_seconds, or if wait_seconds == 0, - process only events that are already queued. - """ +class StepType: + INSTRUCTION = 1 + INSTRUCTION_OVER = 2 + INTO = 3 + OVER = 4 + OUT = 5 - status = None - num_events_handled = 0 - - if self.process is not None: - event = lldb.SBEvent() - old_state = self.process.GetState() - new_state = None - done = False - if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: - # Early-exit if we are in 'boring' states - pass - else: - while not done and self.processListener is not None: - if not self.processListener.PeekAtNextEvent(event): - if wait_seconds > 0: - # No events on the queue, but we are allowed to wait for wait_seconds - # for any events to show up. - self.processListener.WaitForEvent(wait_seconds, event) - new_state = lldb.SBProcess.GetStateFromEvent(event) - - num_events_handled += 1 - - done = not self.processListener.PeekAtNextEvent(event) - else: - # An event is on the queue, process it here. - self.processListener.GetNextEvent(event) - new_state = lldb.SBProcess.GetStateFromEvent(event) - - # continue if stopped after attaching - if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: - self.process.Continue() - - # If needed, perform any event-specific behaviour here - num_events_handled += 1 - - if num_events_handled == 0: - pass - else: - if old_state == new_state: - status = "" - self.ui.update(self.target, status, self, goto_file) + +class LLDBController(object): + """ Handles Vim and LLDB events such as commands and lldb events. """ + + # Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to + # servicing LLDB events from the main UI thread. Usually, we only process events that are already + # sitting on the queue. But in some situations (when we are expecting an event as a result of some + # user interaction) we want to wait for it. The constants below set these wait period in which the + # Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher + # numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at + # times. + eventDelayStep = 2 + eventDelayLaunch = 1 + eventDelayContinue = 1 + + def __init__(self): + """ Creates the LLDB SBDebugger object and initializes the UI class. """ + self.target = None + self.process = None + self.load_dependent_modules = True + + self.dbg = lldb.SBDebugger.Create() + self.commandInterpreter = self.dbg.GetCommandInterpreter() + + self.ui = UI() + + def completeCommand(self, a, l, p): + """ Returns a list of viable completions for command a with length l and cursor at p """ + + assert l[0] == 'L' + # Remove first 'L' character that all commands start with + l = l[1:] + + # Adjust length as string has 1 less character + p = int(p) - 1 + + result = lldb.SBStringList() + num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result) + + if num == -1: + # FIXME: insert completion character... what's a completion + # character? + pass + elif num == -2: + # FIXME: replace line with result.GetStringAtIndex(0) + pass + + if result.GetSize() > 0: + results = filter(None, [result.GetStringAtIndex(x) + for x in range(result.GetSize())]) + return results + else: + return [] + + def doStep(self, stepType): + """ Perform a step command and block the UI for eventDelayStep seconds in order to process + events on lldb's event queue. + FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to + the main thread to avoid the appearance of a "hang". If this happens, the UI will + update whenever; usually when the user moves the cursor. This is somewhat annoying. + """ + if not self.process: + sys.stderr.write("No process to step") + return + + t = self.process.GetSelectedThread() + if stepType == StepType.INSTRUCTION: + t.StepInstruction(False) + if stepType == StepType.INSTRUCTION_OVER: + t.StepInstruction(True) + elif stepType == StepType.INTO: + t.StepInto() + elif stepType == StepType.OVER: + t.StepOver() + elif stepType == StepType.OUT: + t.StepOut() + + self.processPendingEvents(self.eventDelayStep, True) + + def doSelect(self, command, args): + """ Like doCommand, but suppress output when "select" is the first argument.""" + a = args.split(' ') + return self.doCommand(command, args, "select" != a[0], True) + + def doProcess(self, args): + """ Handle 'process' command. If 'launch' is requested, use doLaunch() instead + of the command interpreter to start the inferior process. + """ + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'): + self.doCommand("process", args) + #self.ui.update(self.target, "", self) + else: + self.doLaunch('-s' not in args, "") + + def doAttach(self, process_name): + """ Handle process attach. """ + error = lldb.SBError() + + self.processListener = lldb.SBListener("process_event_listener") + self.target = self.dbg.CreateTarget('') + self.process = self.target.AttachToProcessWithName( + self.processListener, process_name, False, error) + if not error.Success(): + sys.stderr.write("Error during attach: " + str(error)) + return + + self.ui.activate() + self.pid = self.process.GetProcessID() + + print "Attached to %s (pid=%d)" % (process_name, self.pid) + + def doDetach(self): + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Detach() + self.processPendingEvents(self.eventDelayLaunch) + + def doLaunch(self, stop_at_entry, args): + """ Handle process launch. """ + error = lldb.SBError() + + fs = self.target.GetExecutable() + exe = os.path.join(fs.GetDirectory(), fs.GetFilename()) + if self.process is not None and self.process.IsValid(): + pid = self.process.GetProcessID() + state = state_type_to_str(self.process.GetState()) + self.process.Destroy() + + launchInfo = lldb.SBLaunchInfo(args.split(' ')) + self.process = self.target.Launch(launchInfo, error) + if not error.Success(): + sys.stderr.write("Error during launch: " + str(error)) + return + + # launch succeeded, store pid and add some event listeners + self.pid = self.process.GetProcessID() + self.processListener = lldb.SBListener("process_event_listener") + self.process.GetBroadcaster().AddListener( + self.processListener, lldb.SBProcess.eBroadcastBitStateChanged) + + print "Launched %s %s (pid=%d)" % (exe, args, self.pid) + + if not stop_at_entry: + self.doContinue() + else: + self.processPendingEvents(self.eventDelayLaunch) + + def doTarget(self, args): + """ Pass target command to interpreter, except if argument is not one of the valid options, or + is create, in which case try to create a target with the argument as the executable. For example: + target list ==> handled by interpreter + target create blah ==> custom creation of target 'blah' + target blah ==> also creates target blah + """ + target_args = [ # "create", + "delete", + "list", + "modules", + "select", + "stop-hook", + "symbols", + "variable"] + + a = args.split(' ') + if len(args) == 0 or (len(a) > 0 and a[0] in target_args): + self.doCommand("target", args) + return + elif len(a) > 1 and a[0] == "create": + exe = a[1] + elif len(a) == 1 and a[0] not in target_args: + exe = a[0] + + err = lldb.SBError() + self.target = self.dbg.CreateTarget( + exe, None, None, self.load_dependent_modules, err) + if not self.target: + sys.stderr.write( + "Error creating target %s. %s" % + (str(exe), str(err))) + return + + self.ui.activate() + self.ui.update(self.target, "created target %s" % str(exe), self) + + def doContinue(self): + """ Handle 'contiue' command. + FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param. + """ + if not self.process or not self.process.IsValid(): + sys.stderr.write("No process to continue") + return + + self.process.Continue() + self.processPendingEvents(self.eventDelayContinue) + + def doBreakpoint(self, args): + """ Handle breakpoint command with command interpreter, except if the user calls + "breakpoint" with no other args, in which case add a breakpoint at the line + under the cursor. + """ + a = args.split(' ') + if len(args) == 0: + show_output = False + + # User called us with no args, so toggle the bp under cursor + cw = vim.current.window + cb = vim.current.buffer + name = cb.name + line = cw.cursor[0] + + # Since the UI is responsbile for placing signs at bp locations, we have to + # ask it if there already is one or more breakpoints at (file, + # line)... + if self.ui.haveBreakpoint(name, line): + bps = self.ui.getBreakpoints(name, line) + args = "delete %s" % " ".join([str(b.GetID()) for b in bps]) + self.ui.deleteBreakpoints(name, line) + else: + args = "set -f %s -l %d" % (name, line) + else: + show_output = True + + self.doCommand("breakpoint", args, show_output) + return + + def doRefresh(self): + """ process pending events and update UI on request """ + status = self.processPendingEvents() + + def doShow(self, name): + """ handle :Lshow <name> """ + if not name: + self.ui.activate() + return + + if self.ui.showWindow(name): + self.ui.update(self.target, "", self) + + def doHide(self, name): + """ handle :Lhide <name> """ + if self.ui.hideWindow(name): + self.ui.update(self.target, "", self) + + def doExit(self): + self.dbg.Terminate() + self.dbg = None + + def getCommandResult(self, command, command_args): + """ Run cmd in the command interpreter and returns (success, output) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() + if result.Succeeded() else result.GetError()) + + def doCommand( + self, + command, + command_args, + print_on_success=True, + goto_file=False): + """ Run cmd in interpreter and print result (success or failure) on the vim status line. """ + (success, output) = self.getCommandResult(command, command_args) + if success: + self.ui.update(self.target, "", self, goto_file) + if len(output) > 0 and print_on_success: + print output + else: + sys.stderr.write(output) + + def getCommandOutput(self, command, command_args=""): + """ runs cmd in the command interpreter andreturns (status, result) """ + result = lldb.SBCommandReturnObject() + cmd = "%s %s" % (command, command_args) + self.commandInterpreter.HandleCommand(cmd, result) + return (result.Succeeded(), result.GetOutput() + if result.Succeeded() else result.GetError()) + + def processPendingEvents(self, wait_seconds=0, goto_file=True): + """ Handle any events that are queued from the inferior. + Blocks for at most wait_seconds, or if wait_seconds == 0, + process only events that are already queued. + """ + + status = None + num_events_handled = 0 + + if self.process is not None: + event = lldb.SBEvent() + old_state = self.process.GetState() + new_state = None + done = False + if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited: + # Early-exit if we are in 'boring' states + pass + else: + while not done and self.processListener is not None: + if not self.processListener.PeekAtNextEvent(event): + if wait_seconds > 0: + # No events on the queue, but we are allowed to wait for wait_seconds + # for any events to show up. + self.processListener.WaitForEvent( + wait_seconds, event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + num_events_handled += 1 + + done = not self.processListener.PeekAtNextEvent(event) + else: + # An event is on the queue, process it here. + self.processListener.GetNextEvent(event) + new_state = lldb.SBProcess.GetStateFromEvent(event) + + # continue if stopped after attaching + if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped: + self.process.Continue() + + # If needed, perform any event-specific behaviour here + num_events_handled += 1 + + if num_events_handled == 0: + pass + else: + if old_state == new_state: + status = "" + self.ui.update(self.target, status, self, goto_file) def returnCompleteCommand(a, l, p): - """ Returns a "\n"-separated string with possible completion results - for command a with length l and cursor at p. - """ - separator = "\n" - results = ctrl.completeCommand(a, l, p) - vim.command('return "%s%s"' % (separator.join(results), separator)) + """ Returns a "\n"-separated string with possible completion results + for command a with length l and cursor at p. + """ + separator = "\n" + results = ctrl.completeCommand(a, l, p) + vim.command('return "%s%s"' % (separator.join(results), separator)) + def returnCompleteWindow(a, l, p): - """ Returns a "\n"-separated string with possible completion results - for commands that expect a window name parameter (like hide/show). - FIXME: connect to ctrl.ui instead of hardcoding the list here - """ - separator = "\n" - results = ['breakpoints', 'backtrace', 'disassembly', 'locals', 'threads', 'registers'] - vim.command('return "%s%s"' % (separator.join(results), separator)) + """ Returns a "\n"-separated string with possible completion results + for commands that expect a window name parameter (like hide/show). + FIXME: connect to ctrl.ui instead of hardcoding the list here + """ + separator = "\n" + results = [ + 'breakpoints', + 'backtrace', + 'disassembly', + 'locals', + 'threads', + 'registers'] + vim.command('return "%s%s"' % (separator.join(results), separator)) global ctrl ctrl = LLDBController() diff --git a/utils/vim-lldb/python-vim-lldb/plugin.py b/utils/vim-lldb/python-vim-lldb/plugin.py index 694783a95b0e..c59546c745cd 100644 --- a/utils/vim-lldb/python-vim-lldb/plugin.py +++ b/utils/vim-lldb/python-vim-lldb/plugin.py @@ -1,14 +1,16 @@ -# Try to import all dependencies, catch and handle the error gracefully if it fails. +# Try to import all dependencies, catch and handle the error gracefully if +# it fails. import import_lldb try: - import lldb - import vim + import lldb + import vim except ImportError: - sys.stderr.write("Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") - pass + sys.stderr.write( + "Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile") + pass else: - # Everthing went well, so use import to start the plugin controller - from lldb_controller import * + # Everthing went well, so use import to start the plugin controller + from lldb_controller import * diff --git a/utils/vim-lldb/python-vim-lldb/vim_panes.py b/utils/vim-lldb/python-vim-lldb/vim_panes.py index ec537199922c..b0c804d19628 100644 --- a/utils/vim-lldb/python-vim-lldb/vim_panes.py +++ b/utils/vim-lldb/python-vim-lldb/vim_panes.py @@ -6,8 +6,8 @@ # - get_content() - returns a string with the pane contents # # Optionally, to highlight text, implement: -# - get_highlights() - returns a map -# +# - get_highlights() - returns a map +# # And call: # - define_highlight(unique_name, colour) # at some point in the constructor. @@ -16,7 +16,7 @@ # If the pane shows some key-value data that is in the context of a # single frame, inherit from FrameKeyValuePane and implement: # - get_frame_content(self, SBFrame frame) -# +# # # If the pane presents some information that can be retrieved with # a simple LLDB command while the subprocess is stopped, inherit @@ -27,12 +27,12 @@ # Optionally, you can implement: # - get_selected_line() # to highlight a selected line and place the cursor there. -# +# # # FIXME: implement WatchlistPane to displayed watched expressions -# FIXME: define interface for interactive panes, like catching enter +# FIXME: define interface for interactive panes, like catching enter # presses to change selected frame/thread... -# +# import lldb import vim @@ -44,6 +44,8 @@ import sys # ============================================================== # Shamelessly copy/pasted from lldbutil.py in the test suite + + def get_description(obj, option=None): """Calls lldb_obj.GetDescription() and returns a string, or None. @@ -70,512 +72,552 @@ def get_description(obj, option=None): if not success: return None return stream.GetData() - + + def get_selected_thread(target): - """ Returns a tuple with (thread, error) where thread == None if error occurs """ - process = target.GetProcess() - if process is None or not process.IsValid(): - return (None, VimPane.MSG_NO_PROCESS) + """ Returns a tuple with (thread, error) where thread == None if error occurs """ + process = target.GetProcess() + if process is None or not process.IsValid(): + return (None, VimPane.MSG_NO_PROCESS) + + thread = process.GetSelectedThread() + if thread is None or not thread.IsValid(): + return (None, VimPane.MSG_NO_THREADS) + return (thread, "") - thread = process.GetSelectedThread() - if thread is None or not thread.IsValid(): - return (None, VimPane.MSG_NO_THREADS) - return (thread, "") def get_selected_frame(target): - """ Returns a tuple with (frame, error) where frame == None if error occurs """ - (thread, error) = get_selected_thread(target) - if thread is None: - return (None, error) + """ Returns a tuple with (frame, error) where frame == None if error occurs """ + (thread, error) = get_selected_thread(target) + if thread is None: + return (None, error) + + frame = thread.GetSelectedFrame() + if frame is None or not frame.IsValid(): + return (None, VimPane.MSG_NO_FRAME) + return (frame, "") - frame = thread.GetSelectedFrame() - if frame is None or not frame.IsValid(): - return (None, VimPane.MSG_NO_FRAME) - return (frame, "") def _cmd(cmd): - vim.command("call confirm('%s')" % cmd) - vim.command(cmd) + vim.command("call confirm('%s')" % cmd) + vim.command(cmd) + def move_cursor(line, col=0): - """ moves cursor to specified line and col """ - cw = vim.current.window - if cw.cursor[0] != line: - vim.command("execute \"normal %dgg\"" % line) + """ moves cursor to specified line and col """ + cw = vim.current.window + if cw.cursor[0] != line: + vim.command("execute \"normal %dgg\"" % line) + def winnr(): - """ Returns currently selected window number """ - return int(vim.eval("winnr()")) + """ Returns currently selected window number """ + return int(vim.eval("winnr()")) + def bufwinnr(name): - """ Returns window number corresponding with buffer name """ - return int(vim.eval("bufwinnr('%s')" % name)) + """ Returns window number corresponding with buffer name """ + return int(vim.eval("bufwinnr('%s')" % name)) + def goto_window(nr): - """ go to window number nr""" - if nr != winnr(): - vim.command(str(nr) + ' wincmd w') + """ go to window number nr""" + if nr != winnr(): + vim.command(str(nr) + ' wincmd w') + def goto_next_window(): - """ go to next window. """ - vim.command('wincmd w') - return (winnr(), vim.current.buffer.name) + """ go to next window. """ + vim.command('wincmd w') + return (winnr(), vim.current.buffer.name) + def goto_previous_window(): - """ go to previously selected window """ - vim.command("execute \"normal \\<c-w>p\"") + """ go to previously selected window """ + vim.command("execute \"normal \\<c-w>p\"") + def have_gui(): - """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ - return int(vim.eval("has('gui_running')")) == 1 + """ Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """ + return int(vim.eval("has('gui_running')")) == 1 + class PaneLayout(object): - """ A container for a (vertical) group layout of VimPanes """ + """ A container for a (vertical) group layout of VimPanes """ + + def __init__(self): + self.panes = {} + + def havePane(self, name): + """ Returns true if name is a registered pane, False otherwise """ + return name in self.panes + + def prepare(self, panes=[]): + """ Draw panes on screen. If empty list is provided, show all. """ + + # If we can't select a window contained in the layout, we are doing a + # first draw + first_draw = not self.selectWindow(True) + did_first_draw = False + + # Prepare each registered pane + for name in self.panes: + if name in panes or len(panes) == 0: + if first_draw: + # First window in layout will be created with :vsp, and + # closed later + vim.command(":vsp") + first_draw = False + did_first_draw = True + self.panes[name].prepare() + + if did_first_draw: + # Close the split window + vim.command(":q") + + self.selectWindow(False) + + def contains(self, bufferName=None): + """ Returns True if window with name bufferName is contained in the layout, False otherwise. + If bufferName is None, the currently selected window is checked. + """ + if not bufferName: + bufferName = vim.current.buffer.name + + for p in self.panes: + if bufferName is not None and bufferName.endswith(p): + return True + return False + + def selectWindow(self, select_contained=True): + """ Selects a window contained in the layout (if select_contained = True) and returns True. + If select_contained = False, a window that is not contained is selected. Returns False + if no group windows can be selected. + """ + if select_contained == self.contains(): + # Simple case: we are already selected + return True + + # Otherwise, switch to next window until we find a contained window, or + # reach the first window again. + first = winnr() + (curnum, curname) = goto_next_window() + + while not select_contained == self.contains( + curname) and curnum != first: + (curnum, curname) = goto_next_window() + + return self.contains(curname) == select_contained + + def hide(self, panes=[]): + """ Hide panes specified. If empty list provided, hide all. """ + for name in self.panes: + if name in panes or len(panes) == 0: + self.panes[name].destroy() + + def registerForUpdates(self, p): + self.panes[p.name] = p + + def update(self, target, controller): + for name in self.panes: + self.panes[name].update(target, controller) - def __init__(self): - self.panes = {} - def havePane(self, name): - """ Returns true if name is a registered pane, False otherwise """ - return name in self.panes +class VimPane(object): + """ A generic base class for a pane that displays stuff """ + CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' + CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' + CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' + + SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' + SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' + SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' + + MSG_NO_TARGET = "Target does not exist." + MSG_NO_PROCESS = "Process does not exist." + MSG_NO_THREADS = "No valid threads." + MSG_NO_FRAME = "No valid frame." + + # list of defined highlights, so we avoid re-defining them + highlightTypes = [] + + def __init__(self, owner, name, open_below=False, height=3): + self.owner = owner + self.name = name + self.buffer = None + self.maxHeight = 20 + self.openBelow = open_below + self.height = height + self.owner.registerForUpdates(self) + + def isPrepared(self): + """ check window is OK """ + if self.buffer is None or len( + dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: + return False + return True - def prepare(self, panes = []): - """ Draw panes on screen. If empty list is provided, show all. """ + def prepare(self, method='new'): + """ check window is OK, if not then create """ + if not self.isPrepared(): + self.create(method) + + def on_create(self): + pass + + def destroy(self): + """ destroy window """ + if self.buffer is None or len(dir(self.buffer)) == 0: + return + vim.command('bdelete ' + self.name) + + def create(self, method): + """ create window """ + + if method != 'edit': + belowcmd = "below" if self.openBelow else "" + vim.command('silent %s %s %s' % (belowcmd, method, self.name)) + else: + vim.command('silent %s %s' % (method, self.name)) + + self.window = vim.current.window + + # Set LLDB pane options + vim.command("setlocal buftype=nofile") # Don't try to open a file + vim.command("setlocal noswapfile") # Don't use a swap file + vim.command("set nonumber") # Don't display line numbers + # vim.command("set nowrap") # Don't wrap text + + # Save some parameters and reference to buffer + self.buffer = vim.current.buffer + self.width = int(vim.eval("winwidth(0)")) + self.height = int(vim.eval("winheight(0)")) + + self.on_create() + goto_previous_window() + + def update(self, target, controller): + """ updates buffer contents """ + self.target = target + if not self.isPrepared(): + # Window is hidden, or otherwise not ready for an update + return + + original_cursor = self.window.cursor + + # Select pane + goto_window(bufwinnr(self.name)) + + # Clean and update content, and apply any highlights. + self.clean() + + if self.write(self.get_content(target, controller)): + self.apply_highlights() + + cursor = self.get_selected_line() + if cursor is None: + # Place the cursor at its original position in the window + cursor_line = min(original_cursor[0], len(self.buffer)) + cursor_col = min( + original_cursor[1], len( + self.buffer[ + cursor_line - 1])) + else: + # Place the cursor at the location requested by a VimPane + # implementation + cursor_line = min(cursor, len(self.buffer)) + cursor_col = self.window.cursor[1] + + self.window.cursor = (cursor_line, cursor_col) + + goto_previous_window() + + def get_selected_line(self): + """ Returns the line number to move the cursor to, or None to leave + it where the user last left it. + Subclasses implement this to define custom behaviour. + """ + return None - # If we can't select a window contained in the layout, we are doing a first draw - first_draw = not self.selectWindow(True) - did_first_draw = False + def apply_highlights(self): + """ Highlights each set of lines in each highlight group """ + highlights = self.get_highlights() + for highlightType in highlights: + lines = highlights[highlightType] + if len(lines) == 0: + continue + + cmd = 'match %s /' % highlightType + lines = ['\%' + '%d' % line + 'l' for line in lines] + cmd += '\\|'.join(lines) + cmd += '/' + vim.command(cmd) + + def define_highlight(self, name, colour): + """ Defines highlihght """ + if name in VimPane.highlightTypes: + # highlight already defined + return + + vim.command( + "highlight %s ctermbg=%s guibg=%s" % + (name, colour, colour)) + VimPane.highlightTypes.append(name) + + def write(self, msg): + """ replace buffer with msg""" + self.prepare() + + msg = str(msg.encode("utf-8", "replace")).split('\n') + try: + self.buffer.append(msg) + vim.command("execute \"normal ggdd\"") + except vim.error: + # cannot update window; happens when vim is exiting. + return False + + move_cursor(1, 0) + return True - # Prepare each registered pane - for name in self.panes: - if name in panes or len(panes) == 0: - if first_draw: - # First window in layout will be created with :vsp, and closed later - vim.command(":vsp") - first_draw = False - did_first_draw = True - self.panes[name].prepare() + def clean(self): + """ clean all datas in buffer """ + self.prepare() + vim.command(':%d') + #self.buffer[:] = None - if did_first_draw: - # Close the split window - vim.command(":q") + def get_content(self, target, controller): + """ subclasses implement this to provide pane content """ + assert(0 and "pane subclass must implement this") + pass - self.selectWindow(False) + def get_highlights(self): + """ Subclasses implement this to provide pane highlights. + This function is expected to return a map of: + { highlight_name ==> [line_number, ...], ... } + """ + return {} - def contains(self, bufferName = None): - """ Returns True if window with name bufferName is contained in the layout, False otherwise. - If bufferName is None, the currently selected window is checked. - """ - if not bufferName: - bufferName = vim.current.buffer.name - for p in self.panes: - if bufferName is not None and bufferName.endswith(p): - return True - return False +class FrameKeyValuePane(VimPane): - def selectWindow(self, select_contained = True): - """ Selects a window contained in the layout (if select_contained = True) and returns True. - If select_contained = False, a window that is not contained is selected. Returns False - if no group windows can be selected. - """ - if select_contained == self.contains(): - # Simple case: we are already selected - return True + def __init__(self, owner, name, open_below): + """ Initialize parent, define member variables, choose which highlight + to use based on whether or not we have a gui (MacVim/Gvim). + """ + + VimPane.__init__(self, owner, name, open_below) + + # Map-of-maps key/value history { frame --> { variable_name, + # variable_value } } + self.frameValues = {} + + if have_gui(): + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI + else: + self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, + VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) + + def format_pair(self, key, value, changed=False): + """ Formats a key/value pair. Appends a '*' if changed == True """ + marker = '*' if changed else ' ' + return "%s %s = %s\n" % (marker, key, value) + + def get_content(self, target, controller): + """ Get content for a frame-aware pane. Also builds the list of lines that + need highlighting (i.e. changed values.) + """ + if target is None or not target.IsValid(): + return VimPane.MSG_NO_TARGET + + self.changedLines = [] + + (frame, err) = get_selected_frame(target) + if frame is None: + return err + + output = get_description(frame) + lineNum = 1 + + # Retrieve the last values displayed for this frame + frameId = get_description(frame.GetBlock()) + if frameId in self.frameValues: + frameOldValues = self.frameValues[frameId] + else: + frameOldValues = {} + + # Read the frame variables + vals = self.get_frame_content(frame) + for (key, value) in vals: + lineNum += 1 + if len(frameOldValues) == 0 or ( + key in frameOldValues and frameOldValues[key] == value): + output += self.format_pair(key, value) + else: + output += self.format_pair(key, value, True) + self.changedLines.append(lineNum) + + # Save values as oldValues + newValues = {} + for (key, value) in vals: + newValues[key] = value + self.frameValues[frameId] = newValues + + return output + + def get_highlights(self): + ret = {} + ret[self.changedHighlight] = self.changedLines + return ret - # Otherwise, switch to next window until we find a contained window, or reach the first window again. - first = winnr() - (curnum, curname) = goto_next_window() - while not select_contained == self.contains(curname) and curnum != first: - (curnum, curname) = goto_next_window() +class LocalsPane(FrameKeyValuePane): + """ Pane that displays local variables """ - return self.contains(curname) == select_contained + def __init__(self, owner, name='locals'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) - def hide(self, panes = []): - """ Hide panes specified. If empty list provided, hide all. """ - for name in self.panes: - if name in panes or len(panes) == 0: - self.panes[name].destroy() + # FIXME: allow users to customize display of args/locals/statics/scope + self.arguments = True + self.show_locals = True + self.show_statics = True + self.show_in_scope_only = True - def registerForUpdates(self, p): - self.panes[p.name] = p + def format_variable(self, var): + """ Returns a Tuple of strings "(Type) Name", "Value" for SBValue var """ + val = var.GetValue() + if val is None: + # If the value is too big, SBValue.GetValue() returns None; replace + # with ... + val = "..." - def update(self, target, controller): - for name in self.panes: - self.panes[name].update(target, controller) + return ("(%s) %s" % (var.GetTypeName(), var.GetName()), "%s" % val) + def get_frame_content(self, frame): + """ Returns list of key-value pairs of local variables in frame """ + vals = frame.GetVariables(self.arguments, + self.show_locals, + self.show_statics, + self.show_in_scope_only) + return [self.format_variable(x) for x in vals] -class VimPane(object): - """ A generic base class for a pane that displays stuff """ - CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn' - CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed' - CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred' - - SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor' - SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected' - SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue' - - MSG_NO_TARGET = "Target does not exist." - MSG_NO_PROCESS = "Process does not exist." - MSG_NO_THREADS = "No valid threads." - MSG_NO_FRAME = "No valid frame." - - # list of defined highlights, so we avoid re-defining them - highlightTypes = [] - - def __init__(self, owner, name, open_below=False, height=3): - self.owner = owner - self.name = name - self.buffer = None - self.maxHeight = 20 - self.openBelow = open_below - self.height = height - self.owner.registerForUpdates(self) - - def isPrepared(self): - """ check window is OK """ - if self.buffer == None or len(dir(self.buffer)) == 0 or bufwinnr(self.name) == -1: - return False - return True - - def prepare(self, method = 'new'): - """ check window is OK, if not then create """ - if not self.isPrepared(): - self.create(method) - - def on_create(self): - pass - - def destroy(self): - """ destroy window """ - if self.buffer == None or len(dir(self.buffer)) == 0: - return - vim.command('bdelete ' + self.name) - - def create(self, method): - """ create window """ - - if method != 'edit': - belowcmd = "below" if self.openBelow else "" - vim.command('silent %s %s %s' % (belowcmd, method, self.name)) - else: - vim.command('silent %s %s' % (method, self.name)) - - self.window = vim.current.window - - # Set LLDB pane options - vim.command("setlocal buftype=nofile") # Don't try to open a file - vim.command("setlocal noswapfile") # Don't use a swap file - vim.command("set nonumber") # Don't display line numbers - #vim.command("set nowrap") # Don't wrap text - - # Save some parameters and reference to buffer - self.buffer = vim.current.buffer - self.width = int( vim.eval("winwidth(0)") ) - self.height = int( vim.eval("winheight(0)") ) - - self.on_create() - goto_previous_window() - - def update(self, target, controller): - """ updates buffer contents """ - self.target = target - if not self.isPrepared(): - # Window is hidden, or otherwise not ready for an update - return - - original_cursor = self.window.cursor - - # Select pane - goto_window(bufwinnr(self.name)) - - # Clean and update content, and apply any highlights. - self.clean() - - if self.write(self.get_content(target, controller)): - self.apply_highlights() - - cursor = self.get_selected_line() - if cursor is None: - # Place the cursor at its original position in the window - cursor_line = min(original_cursor[0], len(self.buffer)) - cursor_col = min(original_cursor[1], len(self.buffer[cursor_line - 1])) - else: - # Place the cursor at the location requested by a VimPane implementation - cursor_line = min(cursor, len(self.buffer)) - cursor_col = self.window.cursor[1] - - self.window.cursor = (cursor_line, cursor_col) - - goto_previous_window() - - def get_selected_line(self): - """ Returns the line number to move the cursor to, or None to leave - it where the user last left it. - Subclasses implement this to define custom behaviour. - """ - return None - - def apply_highlights(self): - """ Highlights each set of lines in each highlight group """ - highlights = self.get_highlights() - for highlightType in highlights: - lines = highlights[highlightType] - if len(lines) == 0: - continue - - cmd = 'match %s /' % highlightType - lines = ['\%' + '%d' % line + 'l' for line in lines] - cmd += '\\|'.join(lines) - cmd += '/' - vim.command(cmd) - - def define_highlight(self, name, colour): - """ Defines highlihght """ - if name in VimPane.highlightTypes: - # highlight already defined - return - - vim.command("highlight %s ctermbg=%s guibg=%s" % (name, colour, colour)) - VimPane.highlightTypes.append(name) - - def write(self, msg): - """ replace buffer with msg""" - self.prepare() - - msg = str(msg.encode("utf-8", "replace")).split('\n') - try: - self.buffer.append(msg) - vim.command("execute \"normal ggdd\"") - except vim.error: - # cannot update window; happens when vim is exiting. - return False - - move_cursor(1, 0) - return True - - def clean(self): - """ clean all datas in buffer """ - self.prepare() - vim.command(':%d') - #self.buffer[:] = None - - def get_content(self, target, controller): - """ subclasses implement this to provide pane content """ - assert(0 and "pane subclass must implement this") - pass - - def get_highlights(self): - """ Subclasses implement this to provide pane highlights. - This function is expected to return a map of: - { highlight_name ==> [line_number, ...], ... } - """ - return {} +class RegistersPane(FrameKeyValuePane): + """ Pane that displays the contents of registers """ -class FrameKeyValuePane(VimPane): - def __init__(self, owner, name, open_below): - """ Initialize parent, define member variables, choose which highlight - to use based on whether or not we have a gui (MacVim/Gvim). - """ + def __init__(self, owner, name='registers'): + FrameKeyValuePane.__init__(self, owner, name, open_below=True) - VimPane.__init__(self, owner, name, open_below) + def format_register(self, reg): + """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ + name = reg.GetName() + val = reg.GetValue() + if val is None: + val = "..." + return (name, val.strip()) - # Map-of-maps key/value history { frame --> { variable_name, variable_value } } - self.frameValues = {} + def get_frame_content(self, frame): + """ Returns a list of key-value pairs ("name", "value") of registers in frame """ - if have_gui(): - self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI - else: - self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM - self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM, - VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM) - - def format_pair(self, key, value, changed = False): - """ Formats a key/value pair. Appends a '*' if changed == True """ - marker = '*' if changed else ' ' - return "%s %s = %s\n" % (marker, key, value) - - def get_content(self, target, controller): - """ Get content for a frame-aware pane. Also builds the list of lines that - need highlighting (i.e. changed values.) - """ - if target is None or not target.IsValid(): - return VimPane.MSG_NO_TARGET + result = [] + for register_sets in frame.GetRegisters(): + # hack the register group name into the list of registers... + result.append((" = = %s =" % register_sets.GetName(), "")) - self.changedLines = [] + for reg in register_sets: + result.append(self.format_register(reg)) + return result - (frame, err) = get_selected_frame(target) - if frame is None: - return err - output = get_description(frame) - lineNum = 1 +class CommandPane(VimPane): + """ Pane that displays the output of an LLDB command """ - # Retrieve the last values displayed for this frame - frameId = get_description(frame.GetBlock()) - if frameId in self.frameValues: - frameOldValues = self.frameValues[frameId] - else: - frameOldValues = {} - - # Read the frame variables - vals = self.get_frame_content(frame) - for (key, value) in vals: - lineNum += 1 - if len(frameOldValues) == 0 or (key in frameOldValues and frameOldValues[key] == value): - output += self.format_pair(key, value) - else: - output += self.format_pair(key, value, True) - self.changedLines.append(lineNum) - - # Save values as oldValues - newValues = {} - for (key, value) in vals: - newValues[key] = value - self.frameValues[frameId] = newValues - - return output - - def get_highlights(self): - ret = {} - ret[self.changedHighlight] = self.changedLines - return ret + def __init__(self, owner, name, open_below, process_required=True): + VimPane.__init__(self, owner, name, open_below) + self.process_required = process_required -class LocalsPane(FrameKeyValuePane): - """ Pane that displays local variables """ - def __init__(self, owner, name = 'locals'): - FrameKeyValuePane.__init__(self, owner, name, open_below=True) - - # FIXME: allow users to customize display of args/locals/statics/scope - self.arguments = True - self.show_locals = True - self.show_statics = True - self.show_in_scope_only = True - - def format_variable(self, var): - """ Returns a Tuple of strings "(Type) Name", "Value" for SBValue var """ - val = var.GetValue() - if val is None: - # If the value is too big, SBValue.GetValue() returns None; replace with ... - val = "..." - - return ("(%s) %s" % (var.GetTypeName(), var.GetName()), "%s" % val) - - def get_frame_content(self, frame): - """ Returns list of key-value pairs of local variables in frame """ - vals = frame.GetVariables(self.arguments, - self.show_locals, - self.show_statics, - self.show_in_scope_only) - return [self.format_variable(x) for x in vals] + def setCommand(self, command, args=""): + self.command = command + self.args = args -class RegistersPane(FrameKeyValuePane): - """ Pane that displays the contents of registers """ - def __init__(self, owner, name = 'registers'): - FrameKeyValuePane.__init__(self, owner, name, open_below=True) - - def format_register(self, reg): - """ Returns a tuple of strings ("name", "value") for SBRegister reg. """ - name = reg.GetName() - val = reg.GetValue() - if val is None: - val = "..." - return (name, val.strip()) - - def get_frame_content(self, frame): - """ Returns a list of key-value pairs ("name", "value") of registers in frame """ - - result = [] - for register_sets in frame.GetRegisters(): - # hack the register group name into the list of registers... - result.append((" = = %s =" % register_sets.GetName(), "")) - - for reg in register_sets: - result.append(self.format_register(reg)) - return result + def get_content(self, target, controller): + output = "" + if not target: + output = VimPane.MSG_NO_TARGET + elif self.process_required and not target.GetProcess(): + output = VimPane.MSG_NO_PROCESS + else: + (success, output) = controller.getCommandOutput( + self.command, self.args) + return output -class CommandPane(VimPane): - """ Pane that displays the output of an LLDB command """ - def __init__(self, owner, name, open_below, process_required=True): - VimPane.__init__(self, owner, name, open_below) - self.process_required = process_required - - def setCommand(self, command, args = ""): - self.command = command - self.args = args - - def get_content(self, target, controller): - output = "" - if not target: - output = VimPane.MSG_NO_TARGET - elif self.process_required and not target.GetProcess(): - output = VimPane.MSG_NO_PROCESS - else: - (success, output) = controller.getCommandOutput(self.command, self.args) - return output class StoppedCommandPane(CommandPane): - """ Pane that displays the output of an LLDB command when the process is - stopped; otherwise displays process status. This class also implements - highlighting for a single line (to show a single-line selected entity.) - """ - def __init__(self, owner, name, open_below): - """ Initialize parent and define highlight to use for selected line. """ - CommandPane.__init__(self, owner, name, open_below) - if have_gui(): - self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI - else: - self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM - self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, - VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) - - def get_content(self, target, controller): - """ Returns the output of a command that relies on the process being stopped. - If the process is not in 'stopped' state, the process status is returned. + """ Pane that displays the output of an LLDB command when the process is + stopped; otherwise displays process status. This class also implements + highlighting for a single line (to show a single-line selected entity.) """ - output = "" - if not target or not target.IsValid(): - output = VimPane.MSG_NO_TARGET - elif not target.GetProcess() or not target.GetProcess().IsValid(): - output = VimPane.MSG_NO_PROCESS - elif target.GetProcess().GetState() == lldb.eStateStopped: - (success, output) = controller.getCommandOutput(self.command, self.args) - else: - (success, output) = controller.getCommandOutput("process", "status") - return output - def get_highlights(self): - """ Highlight the line under the cursor. Users moving the cursor has - no effect on the selected line. - """ - ret = {} - line = self.get_selected_line() - if line is not None: - ret[self.selectedHighlight] = [line] - return ret - return ret - - def get_selected_line(self): - """ Subclasses implement this to control where the cursor (and selected highlight) - is placed. - """ - return None + def __init__(self, owner, name, open_below): + """ Initialize parent and define highlight to use for selected line. """ + CommandPane.__init__(self, owner, name, open_below) + if have_gui(): + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI + else: + self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM + self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM, + VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM) + + def get_content(self, target, controller): + """ Returns the output of a command that relies on the process being stopped. + If the process is not in 'stopped' state, the process status is returned. + """ + output = "" + if not target or not target.IsValid(): + output = VimPane.MSG_NO_TARGET + elif not target.GetProcess() or not target.GetProcess().IsValid(): + output = VimPane.MSG_NO_PROCESS + elif target.GetProcess().GetState() == lldb.eStateStopped: + (success, output) = controller.getCommandOutput( + self.command, self.args) + else: + (success, output) = controller.getCommandOutput("process", "status") + return output + + def get_highlights(self): + """ Highlight the line under the cursor. Users moving the cursor has + no effect on the selected line. + """ + ret = {} + line = self.get_selected_line() + if line is not None: + ret[self.selectedHighlight] = [line] + return ret + return ret + + def get_selected_line(self): + """ Subclasses implement this to control where the cursor (and selected highlight) + is placed. + """ + return None + class DisassemblyPane(CommandPane): - """ Pane that displays disassembly around PC """ - def __init__(self, owner, name = 'disassembly'): - CommandPane.__init__(self, owner, name, open_below=True) + """ Pane that displays disassembly around PC """ + + def __init__(self, owner, name='disassembly'): + CommandPane.__init__(self, owner, name, open_below=True) + + # FIXME: let users customize the number of instructions to disassemble + self.setCommand("disassemble", "-c %d -p" % self.maxHeight) - # FIXME: let users customize the number of instructions to disassemble - self.setCommand("disassemble", "-c %d -p" % self.maxHeight) class ThreadPane(StoppedCommandPane): - """ Pane that displays threads list """ - def __init__(self, owner, name = 'threads'): - StoppedCommandPane.__init__(self, owner, name, open_below=False) - self.setCommand("thread", "list") + """ Pane that displays threads list """ + + def __init__(self, owner, name='threads'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("thread", "list") # FIXME: the function below assumes threads are listed in sequential order, # which turns out to not be the case. Highlighting of selected thread @@ -592,27 +634,36 @@ class ThreadPane(StoppedCommandPane): # else: # return thread.GetIndexID() + 1 + class BacktracePane(StoppedCommandPane): - """ Pane that displays backtrace """ - def __init__(self, owner, name = 'backtrace'): - StoppedCommandPane.__init__(self, owner, name, open_below=False) - self.setCommand("bt", "") + """ Pane that displays backtrace """ + def __init__(self, owner, name='backtrace'): + StoppedCommandPane.__init__(self, owner, name, open_below=False) + self.setCommand("bt", "") - def get_selected_line(self): - """ Returns the line number in the buffer with the selected frame. - Formula: selected_line = selected_frame_id + 2 - FIXME: the above formula hack does not work when the function return - value is printed in the bt window; the wrong line is highlighted. - """ + def get_selected_line(self): + """ Returns the line number in the buffer with the selected frame. + Formula: selected_line = selected_frame_id + 2 + FIXME: the above formula hack does not work when the function return + value is printed in the bt window; the wrong line is highlighted. + """ + + (frame, err) = get_selected_frame(self.target) + if frame is None: + return None + else: + return frame.GetFrameID() + 2 - (frame, err) = get_selected_frame(self.target) - if frame is None: - return None - else: - return frame.GetFrameID() + 2 class BreakpointsPane(CommandPane): - def __init__(self, owner, name = 'breakpoints'): - super(BreakpointsPane, self).__init__(owner, name, open_below=False, process_required=False) - self.setCommand("breakpoint", "list") + + def __init__(self, owner, name='breakpoints'): + super( + BreakpointsPane, + self).__init__( + owner, + name, + open_below=False, + process_required=False) + self.setCommand("breakpoint", "list") diff --git a/utils/vim-lldb/python-vim-lldb/vim_signs.py b/utils/vim-lldb/python-vim-lldb/vim_signs.py index 926cc29a7fca..94f79ecebe85 100644 --- a/utils/vim-lldb/python-vim-lldb/vim_signs.py +++ b/utils/vim-lldb/python-vim-lldb/vim_signs.py @@ -3,71 +3,79 @@ import vim + class VimSign(object): - SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" - SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" - SIGN_TEXT_PC = "->" - SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' - - # unique sign id (for ':[sign/highlight] define) - sign_id = 1 - - # unique name id (for ':sign place') - name_id = 1 - - # Map of {(sign_text, highlight_colour) --> sign_name} - defined_signs = {} - - def __init__(self, sign_text, buffer, line_number, highlight_colour=None): - """ Define the sign and highlight (if applicable) and show the sign. """ - - # Get the sign name, either by defining it, or looking it up in the map of defined signs - key = (sign_text, highlight_colour) - if not key in VimSign.defined_signs: - name = self.define(sign_text, highlight_colour) - else: - name = VimSign.defined_signs[key] - - self.show(name, buffer.number, line_number) - pass - - def define(self, sign_text, highlight_colour): - """ Defines sign and highlight (if highlight_colour is not None). """ - sign_name = "sign%d" % VimSign.name_id - if highlight_colour is None: - vim.command("sign define %s text=%s" % (sign_name, sign_text)) - else: - self.highlight_name = "highlight%d" % VimSign.name_id - vim.command("highlight %s ctermbg=%s guibg=%s" % (self.highlight_name, - highlight_colour, - highlight_colour)) - vim.command("sign define %s text=%s linehl=%s texthl=%s" % (sign_name, - sign_text, - self.highlight_name, - self.highlight_name)) - VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name - VimSign.name_id += 1 - return sign_name - - - def show(self, name, buffer_number, line_number): - self.id = VimSign.sign_id - VimSign.sign_id += 1 - vim.command("sign place %d name=%s line=%d buffer=%s" % (self.id, name, line_number, buffer_number)) - pass - - def hide(self): - vim.command("sign unplace %d" % self.id) - pass + SIGN_TEXT_BREAKPOINT_RESOLVED = "B>" + SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>" + SIGN_TEXT_PC = "->" + SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue' + + # unique sign id (for ':[sign/highlight] define) + sign_id = 1 + + # unique name id (for ':sign place') + name_id = 1 + + # Map of {(sign_text, highlight_colour) --> sign_name} + defined_signs = {} + + def __init__(self, sign_text, buffer, line_number, highlight_colour=None): + """ Define the sign and highlight (if applicable) and show the sign. """ + + # Get the sign name, either by defining it, or looking it up in the map + # of defined signs + key = (sign_text, highlight_colour) + if key not in VimSign.defined_signs: + name = self.define(sign_text, highlight_colour) + else: + name = VimSign.defined_signs[key] + + self.show(name, buffer.number, line_number) + pass + + def define(self, sign_text, highlight_colour): + """ Defines sign and highlight (if highlight_colour is not None). """ + sign_name = "sign%d" % VimSign.name_id + if highlight_colour is None: + vim.command("sign define %s text=%s" % (sign_name, sign_text)) + else: + self.highlight_name = "highlight%d" % VimSign.name_id + vim.command( + "highlight %s ctermbg=%s guibg=%s" % + (self.highlight_name, highlight_colour, highlight_colour)) + vim.command( + "sign define %s text=%s linehl=%s texthl=%s" % + (sign_name, sign_text, self.highlight_name, self.highlight_name)) + VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name + VimSign.name_id += 1 + return sign_name + + def show(self, name, buffer_number, line_number): + self.id = VimSign.sign_id + VimSign.sign_id += 1 + vim.command("sign place %d name=%s line=%d buffer=%s" % + (self.id, name, line_number, buffer_number)) + pass + + def hide(self): + vim.command("sign unplace %d" % self.id) + pass + class BreakpointSign(VimSign): - def __init__(self, buffer, line_number, is_resolved): - txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED - super(BreakpointSign, self).__init__(txt, buffer, line_number) + + def __init__(self, buffer, line_number, is_resolved): + txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED + super(BreakpointSign, self).__init__(txt, buffer, line_number) + class PCSign(VimSign): - def __init__(self, buffer, line_number, is_selected_thread): - super(PCSign, self).__init__(VimSign.SIGN_TEXT_PC, - buffer, - line_number, - VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) + + def __init__(self, buffer, line_number, is_selected_thread): + super( + PCSign, + self).__init__( + VimSign.SIGN_TEXT_PC, + buffer, + line_number, + VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None) diff --git a/utils/vim-lldb/python-vim-lldb/vim_ui.py b/utils/vim-lldb/python-vim-lldb/vim_ui.py index 4be346b96f0e..33eb6650466d 100644 --- a/utils/vim-lldb/python-vim-lldb/vim_ui.py +++ b/utils/vim-lldb/python-vim-lldb/vim_ui.py @@ -1,235 +1,255 @@ # LLDB UI state in the Vim user interface. -import os, re, sys +import os +import re +import sys import lldb import vim from vim_panes import * from vim_signs import * + def is_same_file(a, b): - """ returns true if paths a and b are the same file """ - a = os.path.realpath(a) - b = os.path.realpath(b) - return a in b or b in a + """ returns true if paths a and b are the same file """ + a = os.path.realpath(a) + b = os.path.realpath(b) + return a in b or b in a + class UI: - def __init__(self): - """ Declare UI state variables """ - - # Default panes to display - self.defaultPanes = ['breakpoints', 'backtrace', 'locals', 'threads', 'registers', 'disassembly'] - - # map of tuples (filename, line) --> SBBreakpoint - self.markedBreakpoints = {} - - # Currently shown signs - self.breakpointSigns = {} - self.pcSigns = [] - - # Container for panes - self.paneCol = PaneLayout() - - # All possible LLDB panes - self.backtracePane = BacktracePane(self.paneCol) - self.threadPane = ThreadPane(self.paneCol) - self.disassemblyPane = DisassemblyPane(self.paneCol) - self.localsPane = LocalsPane(self.paneCol) - self.registersPane = RegistersPane(self.paneCol) - self.breakPane = BreakpointsPane(self.paneCol) - - def activate(self): - """ Activate UI: display default set of panes """ - self.paneCol.prepare(self.defaultPanes) - - def get_user_buffers(self, filter_name=None): - """ Returns a list of buffers that are not a part of the LLDB UI. That is, they - are not contained in the PaneLayout object self.paneCol. - """ - ret = [] - for w in vim.windows: - b = w.buffer - if not self.paneCol.contains(b.name): - if filter_name is None or filter_name in b.name: - ret.append(b) - return ret - - def update_pc(self, process, buffers, goto_file): - """ Place the PC sign on the PC location of each thread's selected frame """ - - def GetPCSourceLocation(thread): - """ Returns a tuple (thread_index, file, line, column) that represents where - the PC sign should be placed for a thread. - """ - - frame = thread.GetSelectedFrame() - frame_num = frame.GetFrameID() - le = frame.GetLineEntry() - while not le.IsValid() and frame_num < thread.GetNumFrames(): - frame_num += 1 - le = thread.GetFrameAtIndex(frame_num).GetLineEntry() - - if le.IsValid(): - path = os.path.join(le.GetFileSpec().GetDirectory(), le.GetFileSpec().GetFilename()) - return (thread.GetIndexID(), path, le.GetLine(), le.GetColumn()) - return None - - - # Clear all existing PC signs - del_list = [] - for sign in self.pcSigns: - sign.hide() - del_list.append(sign) - for sign in del_list: - self.pcSigns.remove(sign) - del sign - - # Select a user (non-lldb) window - if not self.paneCol.selectWindow(False): - # No user window found; avoid clobbering by splitting - vim.command(":vsp") - - # Show a PC marker for each thread - for thread in process: - loc = GetPCSourceLocation(thread) - if not loc: - # no valid source locations for PCs. hide all existing PC markers - continue - - buf = None - (tid, fname, line, col) = loc - buffers = self.get_user_buffers(fname) - is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() - if len(buffers) == 1: - buf = buffers[0] - if buf != vim.current.buffer: - # Vim has an open buffer to the required file: select it - vim.command('execute ":%db"' % buf.number) - elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: - # FIXME: If current buffer is modified, vim will complain when we try to switch away. - # Find a way to detect if the current buffer is modified, and...warn instead? - vim.command('execute ":e %s"' % fname) - buf = vim.current.buffer - elif len(buffers) > 1 and goto_file: - #FIXME: multiple open buffers match PC location - continue - else: - continue - - self.pcSigns.append(PCSign(buf, line, is_selected)) - - if is_selected and goto_file: - # if the selected file has a PC marker, move the cursor there too - curname = vim.current.buffer.name - if curname is not None and is_same_file(curname, fname): - move_cursor(line, 0) - elif move_cursor: - print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) - - def update_breakpoints(self, target, buffers): - """ Decorates buffer with signs corresponding to breakpoints in target. """ - - def GetBreakpointLocations(bp): - """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ - if not bp.IsValid(): - sys.stderr.write("breakpoint is invalid, no locations") - return [] - - ret = [] - numLocs = bp.GetNumLocations() - for i in range(numLocs): - loc = bp.GetLocationAtIndex(i) - desc = get_description(loc, lldb.eDescriptionLevelFull) - match = re.search('at\ ([^:]+):([\d]+)', desc) - try: - lineNum = int(match.group(2).strip()) - ret.append((loc.IsResolved(), match.group(1), lineNum)) - except ValueError as e: - sys.stderr.write("unable to parse breakpoint location line number: '%s'" % match.group(2)) - sys.stderr.write(str(e)) - - return ret - - - if target is None or not target.IsValid(): - return - - needed_bps = {} - for bp_index in range(target.GetNumBreakpoints()): - bp = target.GetBreakpointAtIndex(bp_index) - locations = GetBreakpointLocations(bp) - for (is_resolved, file, line) in GetBreakpointLocations(bp): - for buf in buffers: - if file in buf.name: - needed_bps[(buf, line, is_resolved)] = bp - - # Hide any signs that correspond with disabled breakpoints - del_list = [] - for (b, l, r) in self.breakpointSigns: - if (b, l, r) not in needed_bps: - self.breakpointSigns[(b, l, r)].hide() - del_list.append((b, l, r)) - for d in del_list: - del self.breakpointSigns[d] - - # Show any signs for new breakpoints - for (b, l, r) in needed_bps: - bp = needed_bps[(b, l, r)] - if self.haveBreakpoint(b.name, l): - self.markedBreakpoints[(b.name, l)].append(bp) - else: - self.markedBreakpoints[(b.name, l)] = [bp] - - if (b, l, r) not in self.breakpointSigns: - s = BreakpointSign(b, l, r) - self.breakpointSigns[(b, l, r)] = s - - def update(self, target, status, controller, goto_file=False): - """ Updates debugger info panels and breakpoint/pc marks and prints - status to the vim status line. If goto_file is True, the user's - cursor is moved to the source PC location in the selected frame. - """ - - self.paneCol.update(target, controller) - self.update_breakpoints(target, self.get_user_buffers()) - - if target is not None and target.IsValid(): - process = target.GetProcess() - if process is not None and process.IsValid(): - self.update_pc(process, self.get_user_buffers, goto_file) - - if status is not None and len(status) > 0: - print status - - def haveBreakpoint(self, file, line): - """ Returns True if we have a breakpoint at file:line, False otherwise """ - return (file, line) in self.markedBreakpoints - - def getBreakpoints(self, fname, line): - """ Returns the LLDB SBBreakpoint object at fname:line """ - if self.haveBreakpoint(fname, line): - return self.markedBreakpoints[(fname, line)] - else: - return None - - def deleteBreakpoints(self, name, line): - del self.markedBreakpoints[(name, line)] - - def showWindow(self, name): - """ Shows (un-hides) window pane specified by name """ - if not self.paneCol.havePane(name): - sys.stderr.write("unknown window: %s" % name) - return False - self.paneCol.prepare([name]) - return True - - def hideWindow(self, name): - """ Hides window pane specified by name """ - if not self.paneCol.havePane(name): - sys.stderr.write("unknown window: %s" % name) - return False - self.paneCol.hide([name]) - return True + + def __init__(self): + """ Declare UI state variables """ + + # Default panes to display + self.defaultPanes = [ + 'breakpoints', + 'backtrace', + 'locals', + 'threads', + 'registers', + 'disassembly'] + + # map of tuples (filename, line) --> SBBreakpoint + self.markedBreakpoints = {} + + # Currently shown signs + self.breakpointSigns = {} + self.pcSigns = [] + + # Container for panes + self.paneCol = PaneLayout() + + # All possible LLDB panes + self.backtracePane = BacktracePane(self.paneCol) + self.threadPane = ThreadPane(self.paneCol) + self.disassemblyPane = DisassemblyPane(self.paneCol) + self.localsPane = LocalsPane(self.paneCol) + self.registersPane = RegistersPane(self.paneCol) + self.breakPane = BreakpointsPane(self.paneCol) + + def activate(self): + """ Activate UI: display default set of panes """ + self.paneCol.prepare(self.defaultPanes) + + def get_user_buffers(self, filter_name=None): + """ Returns a list of buffers that are not a part of the LLDB UI. That is, they + are not contained in the PaneLayout object self.paneCol. + """ + ret = [] + for w in vim.windows: + b = w.buffer + if not self.paneCol.contains(b.name): + if filter_name is None or filter_name in b.name: + ret.append(b) + return ret + + def update_pc(self, process, buffers, goto_file): + """ Place the PC sign on the PC location of each thread's selected frame """ + + def GetPCSourceLocation(thread): + """ Returns a tuple (thread_index, file, line, column) that represents where + the PC sign should be placed for a thread. + """ + + frame = thread.GetSelectedFrame() + frame_num = frame.GetFrameID() + le = frame.GetLineEntry() + while not le.IsValid() and frame_num < thread.GetNumFrames(): + frame_num += 1 + le = thread.GetFrameAtIndex(frame_num).GetLineEntry() + + if le.IsValid(): + path = os.path.join( + le.GetFileSpec().GetDirectory(), + le.GetFileSpec().GetFilename()) + return ( + thread.GetIndexID(), + path, + le.GetLine(), + le.GetColumn()) + return None + + # Clear all existing PC signs + del_list = [] + for sign in self.pcSigns: + sign.hide() + del_list.append(sign) + for sign in del_list: + self.pcSigns.remove(sign) + del sign + + # Select a user (non-lldb) window + if not self.paneCol.selectWindow(False): + # No user window found; avoid clobbering by splitting + vim.command(":vsp") + + # Show a PC marker for each thread + for thread in process: + loc = GetPCSourceLocation(thread) + if not loc: + # no valid source locations for PCs. hide all existing PC + # markers + continue + + buf = None + (tid, fname, line, col) = loc + buffers = self.get_user_buffers(fname) + is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID() + if len(buffers) == 1: + buf = buffers[0] + if buf != vim.current.buffer: + # Vim has an open buffer to the required file: select it + vim.command('execute ":%db"' % buf.number) + elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file: + # FIXME: If current buffer is modified, vim will complain when we try to switch away. + # Find a way to detect if the current buffer is modified, + # and...warn instead? + vim.command('execute ":e %s"' % fname) + buf = vim.current.buffer + elif len(buffers) > 1 and goto_file: + # FIXME: multiple open buffers match PC location + continue + else: + continue + + self.pcSigns.append(PCSign(buf, line, is_selected)) + + if is_selected and goto_file: + # if the selected file has a PC marker, move the cursor there + # too + curname = vim.current.buffer.name + if curname is not None and is_same_file(curname, fname): + move_cursor(line, 0) + elif move_cursor: + print "FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname) + + def update_breakpoints(self, target, buffers): + """ Decorates buffer with signs corresponding to breakpoints in target. """ + + def GetBreakpointLocations(bp): + """ Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """ + if not bp.IsValid(): + sys.stderr.write("breakpoint is invalid, no locations") + return [] + + ret = [] + numLocs = bp.GetNumLocations() + for i in range(numLocs): + loc = bp.GetLocationAtIndex(i) + desc = get_description(loc, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + lineNum = int(match.group(2).strip()) + ret.append((loc.IsResolved(), match.group(1), lineNum)) + except ValueError as e: + sys.stderr.write( + "unable to parse breakpoint location line number: '%s'" % + match.group(2)) + sys.stderr.write(str(e)) + + return ret + + if target is None or not target.IsValid(): + return + + needed_bps = {} + for bp_index in range(target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(bp_index) + locations = GetBreakpointLocations(bp) + for (is_resolved, file, line) in GetBreakpointLocations(bp): + for buf in buffers: + if file in buf.name: + needed_bps[(buf, line, is_resolved)] = bp + + # Hide any signs that correspond with disabled breakpoints + del_list = [] + for (b, l, r) in self.breakpointSigns: + if (b, l, r) not in needed_bps: + self.breakpointSigns[(b, l, r)].hide() + del_list.append((b, l, r)) + for d in del_list: + del self.breakpointSigns[d] + + # Show any signs for new breakpoints + for (b, l, r) in needed_bps: + bp = needed_bps[(b, l, r)] + if self.haveBreakpoint(b.name, l): + self.markedBreakpoints[(b.name, l)].append(bp) + else: + self.markedBreakpoints[(b.name, l)] = [bp] + + if (b, l, r) not in self.breakpointSigns: + s = BreakpointSign(b, l, r) + self.breakpointSigns[(b, l, r)] = s + + def update(self, target, status, controller, goto_file=False): + """ Updates debugger info panels and breakpoint/pc marks and prints + status to the vim status line. If goto_file is True, the user's + cursor is moved to the source PC location in the selected frame. + """ + + self.paneCol.update(target, controller) + self.update_breakpoints(target, self.get_user_buffers()) + + if target is not None and target.IsValid(): + process = target.GetProcess() + if process is not None and process.IsValid(): + self.update_pc(process, self.get_user_buffers, goto_file) + + if status is not None and len(status) > 0: + print status + + def haveBreakpoint(self, file, line): + """ Returns True if we have a breakpoint at file:line, False otherwise """ + return (file, line) in self.markedBreakpoints + + def getBreakpoints(self, fname, line): + """ Returns the LLDB SBBreakpoint object at fname:line """ + if self.haveBreakpoint(fname, line): + return self.markedBreakpoints[(fname, line)] + else: + return None + + def deleteBreakpoints(self, name, line): + del self.markedBreakpoints[(name, line)] + + def showWindow(self, name): + """ Shows (un-hides) window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.prepare([name]) + return True + + def hideWindow(self, name): + """ Hides window pane specified by name """ + if not self.paneCol.havePane(name): + sys.stderr.write("unknown window: %s" % name) + return False + self.paneCol.hide([name]) + return True global ui ui = UI() |