1# Copyright (C) 2010-2020 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16import traceback
17import os
18import sys
19import _gdb
20
21if sys.version_info[0] > 2:
22    # Python 3 moved "reload"
23    from imp import reload
24
25from _gdb import *
26
27class _GdbFile (object):
28    # These two are needed in Python 3
29    encoding = "UTF-8"
30    errors = "strict"
31
32    def close(self):
33        # Do nothing.
34        return None
35
36    def isatty(self):
37        return False
38
39    def writelines(self, iterable):
40        for line in iterable:
41            self.write(line)
42
43    def flush(self):
44        flush()
45
46class _GdbOutputFile (_GdbFile):
47    def write(self, s):
48        write(s, stream=STDOUT)
49
50sys.stdout = _GdbOutputFile()
51
52class _GdbOutputErrorFile (_GdbFile):
53    def write(self, s):
54        write(s, stream=STDERR)
55
56sys.stderr = _GdbOutputErrorFile()
57
58# Default prompt hook does nothing.
59prompt_hook = None
60
61# Ensure that sys.argv is set to something.
62# We do not use PySys_SetArgvEx because it did not appear until 2.6.6.
63sys.argv = ['']
64
65# Initial pretty printers.
66pretty_printers = []
67
68# Initial type printers.
69type_printers = []
70# Initial xmethod matchers.
71xmethods = []
72# Initial frame filters.
73frame_filters = {}
74# Initial frame unwinders.
75frame_unwinders = []
76
77def _execute_unwinders(pending_frame):
78    """Internal function called from GDB to execute all unwinders.
79
80    Runs each currently enabled unwinder until it finds the one that
81    can unwind given frame.
82
83    Arguments:
84        pending_frame: gdb.PendingFrame instance.
85    Returns:
86        gdb.UnwindInfo instance or None.
87    """
88    for objfile in objfiles():
89        for unwinder in objfile.frame_unwinders:
90            if unwinder.enabled:
91                unwind_info = unwinder(pending_frame)
92                if unwind_info is not None:
93                    return unwind_info
94
95    for unwinder in current_progspace().frame_unwinders:
96        if unwinder.enabled:
97            unwind_info = unwinder(pending_frame)
98            if unwind_info is not None:
99                return unwind_info
100
101    for unwinder in frame_unwinders:
102        if unwinder.enabled:
103            unwind_info = unwinder(pending_frame)
104            if unwind_info is not None:
105                return unwind_info
106
107    return None
108
109def _execute_file(filepath):
110    """This function is used to replace Python 2's PyRun_SimpleFile.
111
112    Loads and executes the given file.
113
114    We could use the runpy module, but its documentation says:
115    "Furthermore, any functions and classes defined by the executed code are
116    not guaranteed to work correctly after a runpy function has returned."
117    """
118    globals = sys.modules['__main__'].__dict__
119    set_file = False
120    # Set file (if not set) so that the imported file can use it (e.g. to
121    # access file-relative paths). This matches what PyRun_SimpleFile does.
122    if not hasattr(globals, '__file__'):
123        globals['__file__'] = filepath
124        set_file = True
125    try:
126        with open(filepath, 'rb') as file:
127            # We pass globals also as locals to match what Python does
128            # in PyRun_SimpleFile.
129            compiled = compile(file.read(), filepath, 'exec')
130            exec(compiled, globals, globals)
131    finally:
132        if set_file:
133            del globals['__file__']
134
135
136# Convenience variable to GDB's python directory
137PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
138
139# Auto-load all functions/commands.
140
141# Packages to auto-load.
142
143packages = [
144    'function',
145    'command',
146    'printer'
147]
148
149# pkgutil.iter_modules is not available prior to Python 2.6.  Instead,
150# manually iterate the list, collating the Python files in each module
151# path.  Construct the module name, and import.
152
153def _auto_load_packages():
154    for package in packages:
155        location = os.path.join(os.path.dirname(__file__), package)
156        if os.path.exists(location):
157            py_files = filter(lambda x: x.endswith('.py')
158                                        and x != '__init__.py',
159                              os.listdir(location))
160
161            for py_file in py_files:
162                # Construct from foo.py, gdb.module.foo
163                modname = "%s.%s.%s" % ( __name__, package, py_file[:-3] )
164                try:
165                    if modname in sys.modules:
166                        # reload modules with duplicate names
167                        reload(__import__(modname))
168                    else:
169                        __import__(modname)
170                except:
171                    sys.stderr.write (traceback.format_exc() + "\n")
172
173_auto_load_packages()
174
175def GdbSetPythonDirectory(dir):
176    """Update sys.path, reload gdb and auto-load packages."""
177    global PYTHONDIR
178
179    try:
180        sys.path.remove(PYTHONDIR)
181    except ValueError:
182        pass
183    sys.path.insert(0, dir)
184
185    PYTHONDIR = dir
186
187    # note that reload overwrites the gdb module without deleting existing
188    # attributes
189    reload(__import__(__name__))
190    _auto_load_packages()
191
192def current_progspace():
193    "Return the current Progspace."
194    return selected_inferior().progspace
195
196def objfiles():
197    "Return a sequence of the current program space's objfiles."
198    return current_progspace().objfiles()
199
200def solib_name (addr):
201    """solib_name (Long) -> String.\n\
202Return the name of the shared library holding a given address, or None."""
203    return current_progspace().solib_name(addr)
204
205def block_for_pc(pc):
206    "Return the block containing the given pc value, or None."
207    return current_progspace().block_for_pc(pc)
208
209def find_pc_line(pc):
210    """find_pc_line (pc) -> Symtab_and_line.
211Return the gdb.Symtab_and_line object corresponding to the pc value."""
212    return current_progspace().find_pc_line(pc)
213
214try:
215    from pygments import formatters, lexers, highlight
216    def colorize(filename, contents):
217        # Don't want any errors.
218        try:
219            lexer = lexers.get_lexer_for_filename(filename, stripnl=False)
220            formatter = formatters.TerminalFormatter()
221            return highlight(contents, lexer, formatter)
222        except:
223            return None
224except:
225    def colorize(filename, contents):
226        return None
227