brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.3 KiB · a72dad5 Raw
251 lines · python
1##===-- sourcewin.py -----------------------------------------*- Python -*-===##2##3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4# See https://llvm.org/LICENSE.txt for license information.5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6##7##===----------------------------------------------------------------------===##8 9import cui10import curses11import lldb12import lldbutil13import re14import os15 16 17class SourceWin(cui.TitledWin):18    def __init__(self, driver, x, y, w, h):19        super(SourceWin, self).__init__(x, y, w, h, "Source")20        self.sourceman = driver.getSourceManager()21        self.sources = {}22 23        self.filename = None24        self.pc_line = None25        self.viewline = 026 27        self.breakpoints = {}28 29        self.win.scrollok(1)30 31        self.markerPC = ":) "32        self.markerBP = "B> "33        self.markerNone = "   "34 35        try:36            from pygments.formatters import TerminalFormatter37 38            self.formatter = TerminalFormatter()39        except ImportError:40            # self.win.addstr("\nWarning: no 'pygments' library found. Syntax highlighting is disabled.")41            self.lexer = None42            self.formatter = None43            pass44 45        # FIXME: syntax highlight broken46        self.formatter = None47        self.lexer = None48 49    def handleEvent(self, event):50        if isinstance(event, int):51            self.handleKey(event)52            return53 54        if isinstance(event, lldb.SBEvent):55            if lldb.SBBreakpoint.EventIsBreakpointEvent(event):56                self.handleBPEvent(event)57 58            if lldb.SBProcess.EventIsProcessEvent(59                event60            ) and not lldb.SBProcess.GetRestartedFromEvent(event):61                process = lldb.SBProcess.GetProcessFromEvent(event)62                if not process.IsValid():63                    return64                if process.GetState() == lldb.eStateStopped:65                    self.refreshSource(process)66                elif process.GetState() == lldb.eStateExited:67                    self.notifyExited(process)68 69    def notifyExited(self, process):70        self.win.erase()71        target = lldbutil.get_description(process.GetTarget())72        pid = process.GetProcessID()73        ec = process.GetExitStatus()74        self.win.addstr(75            "\nProcess %s [%d] has exited with exit-code %d" % (target, pid, ec)76        )77 78    def pageUp(self):79        if self.viewline > 0:80            self.viewline = self.viewline - 181            self.refreshSource()82 83    def pageDown(self):84        if self.viewline < len(self.content) - self.height + 1:85            self.viewline = self.viewline + 186            self.refreshSource()87        pass88 89    def handleKey(self, key):90        if key == curses.KEY_DOWN:91            self.pageDown()92        elif key == curses.KEY_UP:93            self.pageUp()94 95    def updateViewline(self):96        half = self.height / 297        if self.pc_line < half:98            self.viewline = 099        else:100            self.viewline = self.pc_line - half + 1101 102        if self.viewline < 0:103            raise Exception(104                "negative viewline: pc=%d viewline=%d" % (self.pc_line, self.viewline)105            )106 107    def refreshSource(self, process=None):108        (self.height, self.width) = self.win.getmaxyx()109 110        if process is not None:111            loc = process.GetSelectedThread().GetSelectedFrame().GetLineEntry()112            f = loc.GetFileSpec()113            self.pc_line = loc.GetLine()114 115            if not f.IsValid():116                self.win.addstr(0, 0, "Invalid source file")117                return118 119            self.filename = f.GetFilename()120            path = os.path.join(f.GetDirectory(), self.filename)121            self.setTitle(path)122            self.content = self.getContent(path)123            self.updateViewline()124 125        if self.filename is None:126            return127 128        if self.formatter is not None:129            from pygments.lexers import get_lexer_for_filename130 131            self.lexer = get_lexer_for_filename(self.filename)132 133        bps = (134            []135            if not self.filename in self.breakpoints136            else self.breakpoints[self.filename]137        )138        self.win.erase()139        if self.content:140            self.formatContent(self.content, self.pc_line, bps)141 142    def getContent(self, path):143        content = []144        if path in self.sources:145            content = self.sources[path]146        else:147            if os.path.exists(path):148                with open(path) as x:149                    content = x.readlines()150                self.sources[path] = content151        return content152 153    def formatContent(self, content, pc_line, breakpoints):154        source = ""155        count = 1156        self.win.erase()157        end = min(len(content), self.viewline + self.height)158        for i in range(self.viewline, end):159            line_num = i + 1160            marker = self.markerNone161            attr = curses.A_NORMAL162            if line_num == pc_line:163                attr = curses.A_REVERSE164            if line_num in breakpoints:165                marker = self.markerBP166            line = "%s%3d %s" % (marker, line_num, self.highlight(content[i]))167            if len(line) >= self.width:168                line = line[0 : self.width - 1] + "\n"169            self.win.addstr(line, attr)170            source += line171            count = count + 1172        return source173 174    def highlight(self, source):175        if self.lexer and self.formatter:176            from pygments import highlight177 178            return highlight(source, self.lexer, self.formatter)179        else:180            return source181 182    def addBPLocations(self, locations):183        for path in locations:184            lines = locations[path]185            if path in self.breakpoints:186                self.breakpoints[path].update(lines)187            else:188                self.breakpoints[path] = lines189 190    def removeBPLocations(self, locations):191        for path in locations:192            lines = locations[path]193            if path in self.breakpoints:194                self.breakpoints[path].difference_update(lines)195            else:196                raise "Removing locations that were never added...no good"197 198    def handleBPEvent(self, event):199        def getLocations(event):200            locs = {}201 202            bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event)203 204            if bp.IsInternal():205                # don't show anything for internal breakpoints206                return207 208            for location in bp:209                # hack! getting the LineEntry via SBBreakpointLocation.GetAddress.GetLineEntry does not work good for210                # inlined frames, so we get the description (which does take211                # into account inlined functions) and parse it.212                desc = lldbutil.get_description(location, lldb.eDescriptionLevelFull)213                match = re.search(r"at\ ([^:]+):([\d]+)", desc)214                try:215                    path = match.group(1)216                    line = int(match.group(2).strip())217                except ValueError as e:218                    # bp loc unparsable219                    continue220 221                if path in locs:222                    locs[path].add(line)223                else:224                    locs[path] = set([line])225            return locs226 227        event_type = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event)228        if (229            event_type == lldb.eBreakpointEventTypeEnabled230            or event_type == lldb.eBreakpointEventTypeAdded231            or event_type == lldb.eBreakpointEventTypeLocationsResolved232            or event_type == lldb.eBreakpointEventTypeLocationsAdded233        ):234            self.addBPLocations(getLocations(event))235        elif (236            event_type == lldb.eBreakpointEventTypeRemoved237            or event_type == lldb.eBreakpointEventTypeLocationsRemoved238            or event_type == lldb.eBreakpointEventTypeDisabled239        ):240            self.removeBPLocations(getLocations(event))241        elif (242            event_type == lldb.eBreakpointEventTypeCommandChanged243            or event_type == lldb.eBreakpointEventTypeConditionChanged244            or event_type == lldb.eBreakpointEventTypeIgnoreChanged245            or event_type == lldb.eBreakpointEventTypeThreadChanged246            or event_type == lldb.eBreakpointEventTypeInvalidType247        ):248            # no-op249            pass250        self.refreshSource()251