llvm-project/lldb/source/Interpreter/embedded_interpreter.py

113 lines
3.8 KiB
Python
Raw Normal View History

import __builtin__
import code
import lldb
import sys
import traceback
try:
import readline
import rlcompleter
except ImportError:
have_readline = False
Suppress python readline module under Linux to fix a seg fault. Bug fix for pr18841: http://llvm.org/bugs/show_bug.cgi?id=18841 This change creates a stub Python readline.so module that does almost nothing. Its whole purpose is to prevent Python from loading the real module, something it does during the embedded Python interpreter's initialization sequence (and way before lldb ever requests it within embedded_interpreter.py). On Ubuntu 12.04 and 13.10 x86_64, and in the Python 2.7.6 tree, the stock Python readline module links against the GNU readline library. This appears to be the case on all Pythons except where __APPLE__ is defined. LLDB now requires linking against the libedit library. Something about having both libedit.so and libreadline.so linked into the same process space is causing the Python readline.so to trigger a NULL memory access. I have put in a separate patch to python.org. This suppression of embedded interpreter readline support can be removed if at least any one of the following happens: 1. The stock python distribution accepts a patch similar to what I submitted to Python 2.7.6's Modules/readline.c file. 2. The stock python distribution implements Modules/readline.c in terms of libedit's readline compatibility mode (i.e. essentially compiles it the way __APPLE__ compiles that module) under Linux. 3. a clean-room implementation of the python readline module is implemented against libedit (either readline compatibility mode or native libedit). This could be implemented within the readline.cpp file that this change introduces. It cannot be a fork of python's readline.c module due to llvm licensing. The net effect of this change on Linux is that the embedded python's readline support will not exist. llvm-svn: 202243
2014-02-26 15:39:20 +08:00
except AttributeError:
# This exception gets hit by the rlcompleter when Linux is using
# the readline suppression import.
have_readline = False
else:
have_readline = True
if 'libedit' in readline.__doc__:
readline.parse_and_bind('bind ^I rl_complete')
else:
readline.parse_and_bind('tab: complete')
g_builtin_override_called = False
class LLDBQuitter(object):
def __init__(self, name):
self.name = name
def __repr__(self):
self()
def __call__(self, code=None):
global g_builtin_override_called
g_builtin_override_called = True
raise SystemExit(-1)
def setquit():
'''Redefine builtin functions 'quit()' and 'exit()' to print a message and raise an EOFError exception.'''
# This function will be called prior to each interactive
# interpreter loop or each single line, so we set the global
# g_builtin_override_called to False so we know if a SystemExit
# is thrown, we can catch it and tell the difference between
# a call to "quit()" or "exit()" and something like
# "sys.exit(123)"
global g_builtin_override_called
g_builtin_override_called = False
__builtin__.quit = LLDBQuitter('quit')
__builtin__.exit = LLDBQuitter('exit')
# When running one line, we might place the string to run in this string
# in case it would be hard to correctly escape a string's contents
g_run_one_line_str = None
def get_terminal_size(fd):
try:
import fcntl, termios, struct
hw = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
except:
hw = (0,0)
return hw
def readfunc_stdio(prompt):
sys.stdout.write(prompt)
return sys.stdin.readline().rstrip()
def run_python_interpreter (local_dict):
# Pass in the dictionary, for continuity from one session to the next.
setquit()
try:
fd = sys.stdin.fileno();
interacted = False
if get_terminal_size(fd)[1] == 0:
try:
import termios
old = termios.tcgetattr(fd)
if old[3] & termios.ECHO:
# Need to turn off echoing and restore
new = termios.tcgetattr(fd)
new[3] = new[3] & ~termios.ECHO
try:
termios.tcsetattr(fd, termios.TCSADRAIN, new)
interacted = True
code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()'.", readfunc=readfunc_stdio, local=local_dict)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
except:
pass
# Don't need to turn off echoing
if not interacted:
code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.", readfunc=readfunc_stdio, local=local_dict)
else:
# We have a real interactive terminal
code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.", local=local_dict)
except SystemExit as e:
global g_builtin_override_called
if not g_builtin_override_called:
print 'Script exited with %s' %(e)
def run_one_line (local_dict, input_string):
global g_run_one_line_str
setquit()
try:
repl = code.InteractiveConsole(local_dict);
if input_string:
repl.runsource (input_string)
elif g_run_one_line_str:
repl.runsource (g_run_one_line_str)
except SystemExit as e:
global g_builtin_override_called
if not g_builtin_override_called:
print 'Script exited with %s' %(e)