Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
4e603550
Commit
4e603550
authored
Mar 25, 2011
by
Mark Florisson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Debugger: Added $cy_eval() GDB function
parent
63bcd561
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
92 additions
and
32 deletions
+92
-32
Cython/Debugger/Tests/test_libcython_in_gdb.py
Cython/Debugger/Tests/test_libcython_in_gdb.py
+16
-0
Cython/Debugger/libcython.py
Cython/Debugger/libcython.py
+68
-17
Cython/Debugger/libpython.py
Cython/Debugger/libpython.py
+8
-15
No files found.
Cython/Debugger/Tests/test_libcython_in_gdb.py
View file @
4e603550
...
@@ -378,6 +378,22 @@ class TestExec(DebugTestCase):
...
@@ -378,6 +378,22 @@ class TestExec(DebugTestCase):
gdb
.
execute
(
'cy exec some_random_var = 14'
)
gdb
.
execute
(
'cy exec some_random_var = 14'
)
self
.
assertEqual
(
'14'
,
self
.
eval_command
(
'some_random_var'
))
self
.
assertEqual
(
'14'
,
self
.
eval_command
(
'some_random_var'
))
class
TestCyEval
(
DebugTestCase
):
"Test the $cy_eval() gdb function."
def
test_cy_eval
(
self
):
# This function leaks a few objects in the GDB python process. This
# is no biggie
self
.
break_and_run
(
'os.path.join("foo", "bar")'
)
result
=
gdb
.
execute
(
'print $cy_eval("None")'
,
to_string
=
True
)
assert
re
.
match
(
r'\
$
\d+ = None\n'
,
result
),
result
result
=
gdb
.
execute
(
'print $cy_eval("[a]")'
,
to_string
=
True
)
assert
re
.
match
(
r'\
$
\d+ = \
[
0\
]
', result), result
class TestClosure(DebugTestCase):
class TestClosure(DebugTestCase):
def break_and_run_func(self, funcname):
def break_and_run_func(self, funcname):
...
...
Cython/Debugger/libcython.py
View file @
4e603550
...
@@ -607,6 +607,7 @@ class CyCy(CythonCommand):
...
@@ -607,6 +607,7 @@ class CyCy(CythonCommand):
completer_class
,
prefix
=
True
)
completer_class
,
prefix
=
True
)
commands
=
dict
(
commands
=
dict
(
# GDB commands
import_
=
CyImport
.
register
(),
import_
=
CyImport
.
register
(),
break_
=
CyBreak
.
register
(),
break_
=
CyBreak
.
register
(),
step
=
CyStep
.
register
(),
step
=
CyStep
.
register
(),
...
@@ -624,9 +625,12 @@ class CyCy(CythonCommand):
...
@@ -624,9 +625,12 @@ class CyCy(CythonCommand):
globals
=
CyGlobals
.
register
(),
globals
=
CyGlobals
.
register
(),
exec_
=
libpython
.
FixGdbCommand
(
'cy exec'
,
'-cy-exec'
),
exec_
=
libpython
.
FixGdbCommand
(
'cy exec'
,
'-cy-exec'
),
_exec
=
CyExec
.
register
(),
_exec
=
CyExec
.
register
(),
# GDB functions
cy_cname
=
CyCName
(
'cy_cname'
),
cy_cname
=
CyCName
(
'cy_cname'
),
cy_cvalue
=
CyCValue
(
'cy_cvalue'
),
cy_cvalue
=
CyCValue
(
'cy_cvalue'
),
cy_lineno
=
CyLine
(
'cy_lineno'
),
cy_lineno
=
CyLine
(
'cy_lineno'
),
cy_eval
=
CyEval
(
'cy_eval'
),
)
)
for
command_name
,
command
in
commands
.
iteritems
():
for
command_name
,
command
in
commands
.
iteritems
():
...
@@ -1169,15 +1173,14 @@ class CyGlobals(CyLocals):
...
@@ -1169,15 +1173,14 @@ class CyGlobals(CyLocals):
max_name_length
,
' '
)
max_name_length
,
' '
)
class
CyExec
(
CythonCommand
,
libpython
.
PyExec
):
class
EvaluateOrExecuteCodeMixin
(
object
):
"""
"""
Execute Python code in the nearest Python or Cython frame.
Evaluate or execute Python code in a Cython or Python frame. The 'evalcode'
method evaluations Python code, prints a traceback if an exception went
uncaught, and returns any return value as a gdb.Value (NULL on exception).
"""
"""
name
=
'-cy-exec'
command_class
=
gdb
.
COMMAND_STACK
completer_class
=
gdb
.
COMPLETE_NONE
def
_fill_locals_dict
(
self
,
executor
,
local_dict_pointer
):
def
_fill_locals_dict
(
self
,
executor
,
local_dict_pointer
):
"Fill a remotely allocated dict with values from the Cython C stack"
"Fill a remotely allocated dict with values from the Cython C stack"
cython_func
=
self
.
get_cython_function
()
cython_func
=
self
.
get_cython_function
()
...
@@ -1208,28 +1211,22 @@ class CyExec(CythonCommand, libpython.PyExec):
...
@@ -1208,28 +1211,22 @@ class CyExec(CythonCommand, libpython.PyExec):
raise
gdb
.
GdbError
(
"Unable to execute Python code."
)
raise
gdb
.
GdbError
(
"Unable to execute Python code."
)
finally
:
finally
:
# PyDict_SetItem doesn't steal our reference
# PyDict_SetItem doesn't steal our reference
executor
.
decref
(
pystringp
)
executor
.
x
decref
(
pystringp
)
def
_find_first_cython_or_python_frame
(
self
):
def
_find_first_cython_or_python_frame
(
self
):
frame
=
gdb
.
selected_frame
()
frame
=
gdb
.
selected_frame
()
while
frame
:
while
frame
:
if
(
self
.
is_cython_function
(
frame
)
or
if
(
self
.
is_cython_function
(
frame
)
or
self
.
is_python_function
(
frame
)):
self
.
is_python_function
(
frame
)):
frame
.
select
()
return
frame
return
frame
frame
=
frame
.
older
()
frame
=
frame
.
older
()
raise
gdb
.
GdbError
(
"There is no Cython or Python frame on the stack."
)
raise
gdb
.
GdbError
(
"There is no Cython or Python frame on the stack."
)
def
invoke
(
self
,
expr
,
from_tty
):
frame
=
self
.
_find_first_cython_or_python_frame
()
if
self
.
is_python_function
(
frame
):
libpython
.
py_exec
.
invoke
(
expr
,
from_tty
)
return
expr
,
input_type
=
self
.
readcode
(
expr
)
executor
=
libpython
.
PythonCodeExecutor
()
def
_evalcode_cython
(
self
,
executor
,
code
,
input_type
):
with
libpython
.
FetchAndRestoreError
():
with
libpython
.
FetchAndRestoreError
():
# get the dict of Cython globals and construct a dict in the
# get the dict of Cython globals and construct a dict in the
# inferior with Cython locals
# inferior with Cython locals
...
@@ -1240,9 +1237,51 @@ class CyExec(CythonCommand, libpython.PyExec):
...
@@ -1240,9 +1237,51 @@ class CyExec(CythonCommand, libpython.PyExec):
try
:
try
:
self
.
_fill_locals_dict
(
executor
,
self
.
_fill_locals_dict
(
executor
,
libpython
.
pointervalue
(
local_dict
))
libpython
.
pointervalue
(
local_dict
))
executor
.
evalcode
(
expr
,
input_type
,
global_dict
,
local_dict
)
result
=
executor
.
evalcode
(
code
,
input_type
,
global_dict
,
local_dict
)
finally
:
finally
:
executor
.
decref
(
libpython
.
pointervalue
(
local_dict
))
executor
.
xdecref
(
libpython
.
pointervalue
(
local_dict
))
return
result
def
_evalcode_python
(
self
,
executor
,
code
,
input_type
):
global_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetGlobals()'
)
local_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetLocals()'
)
if
(
libpython
.
pointervalue
(
global_dict
)
==
0
or
libpython
.
pointervalue
(
local_dict
)
==
0
):
raise
gdb
.
GdbError
(
"Unable to find the locals or globals of the "
"most recent Python function (relative to the "
"selected frame)."
)
return
executor
.
evalcode
(
code
,
input_type
,
global_dict
,
local_dict
)
def
evalcode
(
self
,
code
,
input_type
):
"""
Evaluate `code` in a Python or Cython stack frame using the given
`input_type`.
"""
frame
=
self
.
_find_first_cython_or_python_frame
()
executor
=
libpython
.
PythonCodeExecutor
()
if
self
.
is_python_function
(
frame
):
return
self
.
_evalcode_python
(
executor
,
code
,
input_type
)
return
self
.
_evalcode_cython
(
executor
,
code
,
input_type
)
class
CyExec
(
CythonCommand
,
libpython
.
PyExec
,
EvaluateOrExecuteCodeMixin
):
"""
Execute Python code in the nearest Python or Cython frame.
"""
name
=
'-cy-exec'
command_class
=
gdb
.
COMMAND_STACK
completer_class
=
gdb
.
COMPLETE_NONE
def
invoke
(
self
,
expr
,
from_tty
):
expr
,
input_type
=
self
.
readcode
(
expr
)
executor
=
libpython
.
PythonCodeExecutor
()
executor
.
xdecref
(
self
.
evalcode
(
expr
,
executor
.
Py_single_input
))
# Functions
# Functions
...
@@ -1312,6 +1351,18 @@ class CyLine(gdb.Function, CythonBase):
...
@@ -1312,6 +1351,18 @@ class CyLine(gdb.Function, CythonBase):
def
invoke
(
self
):
def
invoke
(
self
):
return
self
.
get_cython_lineno
()
return
self
.
get_cython_lineno
()
class
CyEval
(
gdb
.
Function
,
CythonBase
,
EvaluateOrExecuteCodeMixin
):
"""
Evaluate Python code in the nearest Python or Cython frame and return
"""
@
gdb_function_value_to_unicode
def
invoke
(
self
,
python_expression
):
input_type
=
libpython
.
PythonCodeExecutor
.
Py_eval_input
return
self
.
evalcode
(
python_expression
,
input_type
)
cython_info
=
CythonInfo
()
cython_info
=
CythonInfo
()
cy
=
CyCy
.
register
()
cy
=
CyCy
.
register
()
cython_info
.
cy
=
cy
cython_info
.
cy
=
cy
...
...
Cython/Debugger/libpython.py
View file @
4e603550
...
@@ -2190,12 +2190,12 @@ class PythonInfo(LanguageInfo):
...
@@ -2190,12 +2190,12 @@ class PythonInfo(LanguageInfo):
try:
try:
tstate = frame.read_var('
tstate
').dereference()
tstate = frame.read_var('
tstate
').dereference()
if gdb.parse_and_eval('
tstate
->
frame
==
f'):
if gdb.parse_and_eval('
tstate
->
frame
==
f'):
# tstate local variable initialized
# tstate local variable initialized
, check for an exception
inf_type = tstate['
curexc_type
']
inf_type = tstate['
curexc_type
']
inf_value = tstate['
curexc_value
']
inf_value = tstate['
curexc_value
']
if inf_type:
if inf_type:
return '
An
exception
was
raised
:
%
s
(
%
s
)
' % (inf_type,
return '
An
exception
was
raised
:
%
s
(
%
s
)
' % (inf_value,)
inf_value)
except (ValueError, RuntimeError), e:
except (ValueError, RuntimeError), e:
# Could not read the variable tstate or it'
s
memory
,
it
's ok
# Could not read the variable tstate or it'
s
memory
,
it
's ok
pass
pass
...
@@ -2342,7 +2342,7 @@ class PythonCodeExecutor(object):
...
@@ -2342,7 +2342,7 @@ class PythonCodeExecutor(object):
"Increment the reference count of a Python object in the inferior."
"Increment the reference count of a Python object in the inferior."
gdb
.
parse_and_eval
(
'Py_IncRef((PyObject *) %d)'
%
pointer
)
gdb
.
parse_and_eval
(
'Py_IncRef((PyObject *) %d)'
%
pointer
)
def
decref
(
self
,
pointer
):
def
x
decref
(
self
,
pointer
):
"Decrement the reference count of a Python object in the inferior."
"Decrement the reference count of a Python object in the inferior."
# Py_DecRef is like Py_XDECREF, but a function. So we don't have
# Py_DecRef is like Py_XDECREF, but a function. So we don't have
# to check for NULL. This should also decref all our allocated
# to check for NULL. This should also decref all our allocated
...
@@ -2382,10 +2382,11 @@ class PythonCodeExecutor(object):
...
@@ -2382,10 +2382,11 @@ class PythonCodeExecutor(object):
with
FetchAndRestoreError
():
with
FetchAndRestoreError
():
try
:
try
:
self
.
decref
(
gdb
.
parse_and_eval
(
code
)
)
pyobject_return_value
=
gdb
.
parse_and_eval
(
code
)
finally
:
finally
:
self
.
free
(
pointer
)
self
.
free
(
pointer
)
return
pyobject_return_value
class
FetchAndRestoreError
(
PythonCodeExecutor
):
class
FetchAndRestoreError
(
PythonCodeExecutor
):
"""
"""
...
@@ -2484,17 +2485,9 @@ class PyExec(gdb.Command):
...
@@ -2484,17 +2485,9 @@ class PyExec(gdb.Command):
def
invoke
(
self
,
expr
,
from_tty
):
def
invoke
(
self
,
expr
,
from_tty
):
expr
,
input_type
=
self
.
readcode
(
expr
)
expr
,
input_type
=
self
.
readcode
(
expr
)
executor
=
PythonCodeExecutor
()
executor
=
PythonCodeExecutor
()
global_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetGlobals()'
)
result
=
executor
.
evalcode
(
expr
,
input_type
,
global_dict
,
local_dict
)
local_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetLocals()'
)
executor
.
xdecref
(
result
)
if
pointervalue
(
global_dict
)
==
0
or
pointervalue
(
local_dict
)
==
0
:
raise
gdb
.
GdbError
(
"Unable to find the locals or globals of the "
"most recent Python function (relative to the "
"selected frame)."
)
executor
.
evalcode
(
expr
,
input_type
,
global_dict
,
local_dict
)
gdb
.
execute
(
'set breakpoint pending on'
)
gdb
.
execute
(
'set breakpoint pending on'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment