2626 # This is what "no gdb" looks like. There may, however, be other
2727 # errors that manifest this way too.
2828 raise unittest .SkipTest ("Couldn't find gdb on the path" )
29- gdb_version_number = re .search (b"^GNU gdb [^\d]*(\d+)\." , gdb_version )
30- if int (gdb_version_number .group (1 )) < 7 :
29+ gdb_version_number = re .search (b"^GNU gdb [^\d]*(\d+)\.(\d)" , gdb_version )
30+ gdb_major_version = int (gdb_version_number .group (1 ))
31+ gdb_minor_version = int (gdb_version_number .group (2 ))
32+ if gdb_major_version < 7 :
3133 raise unittest .SkipTest ("gdb versions before 7.0 didn't support python embedding"
3234 " Saw:\n " + gdb_version .decode ('ascii' , 'replace' ))
3335
3436if not sysconfig .is_python_build ():
3537 raise unittest .SkipTest ("test_gdb only works on source builds at the moment." )
3638
39+ # Location of custom hooks file in a repository checkout.
40+ checkout_hook_path = os .path .join (os .path .dirname (sys .executable ),
41+ 'python-gdb.py' )
42+
43+ def run_gdb (* args , ** env_vars ):
44+ """Runs gdb in --batch mode with the additional arguments given by *args.
45+
46+ Returns its (stdout, stderr) decoded from utf-8 using the replace handler.
47+ """
48+ if env_vars :
49+ env = os .environ .copy ()
50+ env .update (env_vars )
51+ else :
52+ env = None
53+ base_cmd = ('gdb' , '--batch' )
54+ if (gdb_major_version , gdb_minor_version ) >= (7 , 4 ):
55+ base_cmd += ('-iex' , 'add-auto-load-safe-path ' + checkout_hook_path )
56+ out , err = subprocess .Popen (base_cmd + args ,
57+ stdout = subprocess .PIPE , stderr = subprocess .PIPE , env = env ,
58+ ).communicate ()
59+ return out .decode ('utf-8' , 'replace' ), err .decode ('utf-8' , 'replace' )
60+
3761# Verify that "gdb" was built with the embedded python support enabled:
38- cmd = "--eval-command=python import sys; print sys.version_info"
39- p = subprocess .Popen (["gdb" , "--batch" , cmd ],
40- stdout = subprocess .PIPE )
41- gdbpy_version , _ = p .communicate ()
42- if gdbpy_version == b'' :
62+ gdbpy_version , _ = run_gdb ("--eval-command=python import sys; print sys.version_info" )
63+ if not gdbpy_version :
4364 raise unittest .SkipTest ("gdb not built with embedded python support" )
4465
45- # Verify that "gdb" can load our custom hooks
46- p = subprocess .Popen (["gdb" , "--batch" , cmd ,
47- "--args" , sys .executable ],
48- stdout = subprocess .PIPE , stderr = subprocess .PIPE )
49- __ , gdbpy_errors = p .communicate ()
50- if b"auto-loading has been declined" in gdbpy_errors :
51- msg = "gdb security settings prevent use of custom hooks: %s"
52- raise unittest .SkipTest (msg % gdbpy_errors )
66+ # Verify that "gdb" can load our custom hooks. In theory this should never fail.
67+ cmd = ['--args' , sys .executable ]
68+ _ , gdbpy_errors = run_gdb ('--args' , sys .executable )
69+ if "auto-loading has been declined" in gdbpy_errors :
70+ msg = "gdb security settings prevent use of custom hooks: "
71+ raise unittest .SkipTest (msg + gdbpy_errors .rstrip ())
5372
5473def gdb_has_frame_select ():
5574 # Does this build of gdb have gdb.Frame.select ?
56- cmd = "--eval-command=python print(dir(gdb.Frame))"
57- p = subprocess .Popen (["gdb" , "--batch" , cmd ],
58- stdout = subprocess .PIPE )
59- stdout , _ = p .communicate ()
60- m = re .match (br'.*\[(.*)\].*' , stdout )
75+ stdout , _ = run_gdb ("--eval-command=python print(dir(gdb.Frame))" )
76+ m = re .match (r'.*\[(.*)\].*' , stdout )
6177 if not m :
6278 raise unittest .SkipTest ("Unable to parse output from gdb.Frame.select test" )
63- gdb_frame_dir = m .group (1 ).split (b ', ' )
64- return b "'select'" in gdb_frame_dir
79+ gdb_frame_dir = m .group (1 ).split (', ' )
80+ return "'select'" in gdb_frame_dir
6581
6682HAS_PYUP_PYDOWN = gdb_has_frame_select ()
6783
@@ -71,21 +87,6 @@ class DebuggerTests(unittest.TestCase):
7187
7288 """Test that the debugger can debug Python."""
7389
74- def run_gdb (self , * args , ** env_vars ):
75- """Runs gdb with the command line given by *args.
76-
77- Returns its stdout, stderr
78- """
79- if env_vars :
80- env = os .environ .copy ()
81- env .update (env_vars )
82- else :
83- env = None
84- out , err = subprocess .Popen (
85- args , stdout = subprocess .PIPE , stderr = subprocess .PIPE , env = env ,
86- ).communicate ()
87- return out .decode ('utf-8' , 'replace' ), err .decode ('utf-8' , 'replace' )
88-
8990 def get_stack_trace (self , source = None , script = None ,
9091 breakpoint = BREAKPOINT_FN ,
9192 cmds_after_breakpoint = None ,
@@ -142,7 +143,7 @@ def get_stack_trace(self, source=None, script=None,
142143 # print ' '.join(args)
143144
144145 # Use "args" to invoke gdb, capturing stdout, stderr:
145- out , err = self . run_gdb (* args , PYTHONHASHSEED = '0' )
146+ out , err = run_gdb (* args , PYTHONHASHSEED = '0' )
146147
147148 # Ignore some noise on stderr due to the pending breakpoint:
148149 err = err .replace ('Function "%s" not defined.\n ' % breakpoint , '' )
@@ -159,6 +160,11 @@ def get_stack_trace(self, source=None, script=None,
159160 'Do you need "set solib-search-path" or '
160161 '"set sysroot"?\n ' ,
161162 '' )
163+ err = err .replace ('warning: Could not load shared library symbols for '
164+ 'linux-gate.so.1.\n '
165+ 'Do you need "set solib-search-path" or '
166+ '"set sysroot"?\n ' ,
167+ '' )
162168
163169 # Ensure no unexpected error messages:
164170 self .assertEqual (err , '' )
0 commit comments