-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-34989: python-gdb.py: fix current_line_num() #9889
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
python-gdb.py now handles errors on computing the line number of a Python | ||
frame. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -934,35 +934,50 @@ def current_line_num(self): | |
if long(f_trace) != 0: | ||
# we have a non-NULL f_trace: | ||
return self.f_lineno | ||
else: | ||
#try: | ||
|
||
try: | ||
return self.co.addr2line(self.f_lasti) | ||
#except ValueError: | ||
# return self.f_lineno | ||
except Exception: | ||
# bpo-34989: addr2line() is a complex function, it can fail in many | ||
# ways. For example, it fails with a TypeError on "FakeRepr" if | ||
# gdb fails to load debug symbols. Use a catch-all "except | ||
# Exception" to make the whole function safe. The caller has to | ||
# handle None anyway for optimized Python. | ||
return None | ||
|
||
def current_line(self): | ||
'''Get the text of the current source line as a string, with a trailing | ||
newline character''' | ||
if self.is_optimized_out(): | ||
return '(frame information optimized out)' | ||
|
||
lineno = self.current_line_num() | ||
if lineno is None: | ||
return '(failed to get frame line number)' | ||
|
||
filename = self.filename() | ||
try: | ||
f = open(os_fsencode(filename), 'r') | ||
with open(os_fsencode(filename), 'r') as fp: | ||
lines = fp.readlines() | ||
except IOError: | ||
return None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code mimicks linecache.getline() which is used to render a traceback. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be honest, I was also surprised at the first read, and I had to double check when I saw your comment :-D |
||
with f: | ||
all_lines = f.readlines() | ||
# Convert from 1-based current_line_num to 0-based list offset: | ||
return all_lines[self.current_line_num()-1] | ||
|
||
try: | ||
# Convert from 1-based current_line_num to 0-based list offset | ||
return lines[lineno - 1] | ||
except IndexError: | ||
return None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. If we have an index error that means the file did not match. Maybe we should say this to the user? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto, linecache.getline() behaves the same, and the code mimicks linecache's behaviour. |
||
|
||
def write_repr(self, out, visited): | ||
if self.is_optimized_out(): | ||
out.write('(frame information optimized out)') | ||
return | ||
out.write('Frame 0x%x, for file %s, line %i, in %s (' | ||
lineno = self.current_line_num() | ||
lineno = str(lineno) if lineno is not None else "?" | ||
out.write('Frame 0x%x, for file %s, line %s, in %s (' | ||
% (self.as_address(), | ||
self.co_filename.proxyval(visited), | ||
self.current_line_num(), | ||
lineno, | ||
self.co_name.proxyval(visited))) | ||
first = True | ||
for pyop_name, pyop_value in self.iter_locals(): | ||
|
@@ -981,9 +996,11 @@ def print_traceback(self): | |
sys.stdout.write(' (frame information optimized out)\n') | ||
return | ||
visited = set() | ||
sys.stdout.write(' File "%s", line %i, in %s\n' | ||
lineno = self.current_line_num() | ||
lineno = str(lineno) if lineno is not None else "?" | ||
sys.stdout.write(' File "%s", line %s, in %s\n' | ||
% (self.co_filename.proxyval(visited), | ||
self.current_line_num(), | ||
lineno, | ||
self.co_name.proxyval(visited))) | ||
|
||
class PySetObjectPtr(PyObjectPtr): | ||
|
@@ -1732,6 +1749,9 @@ def invoke(self, args, from_tty): | |
|
||
filename = pyop.filename() | ||
lineno = pyop.current_line_num() | ||
if lineno is None: | ||
print('Unable to read python frame line number') | ||
return | ||
|
||
if start is None: | ||
start = lineno - 5 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiny nit: that could also have a blank line after to make it obvious you're returning early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I concur, done.