diff options
Diffstat (limited to 'lldb/utils/lui')
-rw-r--r-- | lldb/utils/lui/breakwin.py | 150 | ||||
-rw-r--r-- | lldb/utils/lui/commandwin.py | 222 | ||||
-rwxr-xr-x | lldb/utils/lui/cui.py | 589 | ||||
-rw-r--r-- | lldb/utils/lui/debuggerdriver.py | 75 | ||||
-rw-r--r-- | lldb/utils/lui/eventwin.py | 30 | ||||
-rw-r--r-- | lldb/utils/lui/lldbutil.py | 344 | ||||
-rwxr-xr-x | lldb/utils/lui/lui.py | 191 | ||||
-rwxr-xr-x | lldb/utils/lui/sandbox.py | 96 | ||||
-rw-r--r-- | lldb/utils/lui/sourcewin.py | 443 | ||||
-rw-r--r-- | lldb/utils/lui/statuswin.py | 54 |
10 files changed, 1200 insertions, 994 deletions
diff --git a/lldb/utils/lui/breakwin.py b/lldb/utils/lui/breakwin.py index 734f5eddba4..7ecb78fd103 100644 --- a/lldb/utils/lui/breakwin.py +++ b/lldb/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/lldb/utils/lui/commandwin.py b/lldb/utils/lui/commandwin.py index 2eb2082c6c8..f778d736ec5 100644 --- a/lldb/utils/lui/commandwin.py +++ b/lldb/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/lldb/utils/lui/cui.py b/lldb/utils/lui/cui.py index e82f0abac2c..963606a0d52 100755 --- a/lldb/utils/lui/cui.py +++ b/lldb/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/lldb/utils/lui/debuggerdriver.py b/lldb/utils/lui/debuggerdriver.py index f7b885107cc..48de10d79f3 100644 --- a/lldb/utils/lui/debuggerdriver.py +++ b/lldb/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/lldb/utils/lui/eventwin.py b/lldb/utils/lui/eventwin.py index 327978a3b45..8ad8d3a8c49 100644 --- a/lldb/utils/lui/eventwin.py +++ b/lldb/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/lldb/utils/lui/lldbutil.py b/lldb/utils/lui/lldbutil.py index 8bdb074728f..b88a10a44fb 100644 --- a/lldb/utils/lui/lldbutil.py +++ b/lldb/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/lldb/utils/lui/lui.py b/lldb/utils/lui/lui.py index 31b152c77f0..9b473f5ff82 100755 --- a/lldb/utils/lui/lui.py +++ b/lldb/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/lldb/utils/lui/sandbox.py b/lldb/utils/lui/sandbox.py index 5a3a64cba69..93b3c23138f 100755 --- a/lldb/utils/lui/sandbox.py +++ b/lldb/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/lldb/utils/lui/sourcewin.py b/lldb/utils/lui/sourcewin.py index 5e7067fdebe..50d2f2d3e76 100644 --- a/lldb/utils/lui/sourcewin.py +++ b/lldb/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/lldb/utils/lui/statuswin.py b/lldb/utils/lui/statuswin.py index c6f6c990b34..3dc34ef1bc8 100644 --- a/lldb/utils/lui/statuswin.py +++ b/lldb/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 |