Skip to content
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

bpo-45637: Remove broken fallback in gdb helpers to obtain frame variable #29257

Merged
merged 1 commit into from
Nov 9, 2021

Conversation

pablogsal
Copy link
Member

@pablogsal pablogsal commented Oct 27, 2021

@pablogsal
Copy link
Member Author

This will not fix the buildbot, but at least won't give incorrect results. We need to make sure that we bail out if the frame is not optimized, but that must be done separately

@pablogsal
Copy link
Member Author

@markshannon We should maybe place the current frame in some place that we know is not going to get optimized so we can retrieve it

@markshannon
Copy link
Member

@markshannon We should maybe place the current frame in some place that we know is not going to get optimized so we can retrieve it

Yes, let's do that.

@markshannon
Copy link
Member

But let's do it properly, and not in this PR. Could we restrict this PR to fixing gdb support, thanks.

If we move the frame to the cframe, then it should be removed from the thread state.
I'm benchmarking a PR to do that now.

@pablogsal
Copy link
Member Author

pablogsal commented Oct 28, 2021

But let's do it properly, and not in this PR. Could we restrict this PR to fixing gdb support, thanks.

If we move the frame to the cframe, then it should be removed from the thread state. I'm benchmarking a PR to do that now.

The current frame in the thread state is what makes external inspection tools work. Of you remove it from there you make it impossible to fetch the current frame from the _PyRuntime structure. That's a no go

Or are you talking about removing cframe from the thread state?

@pablogsal
Copy link
Member Author

I think this approach is the best. We cannot just remove the bad gdb part because other tests rely on it unfortunately, so we are currently in this half broken state.

Adding a redundant current frame to the CFrame is a negligible cost for having the GDB bindings work on all these cases

@pablogsal
Copy link
Member Author

pablogsal commented Oct 28, 2021

For some reason, removing the fallback this breaks test_threads in the address sanitizer:

======================================================================
FAIL: test_threads (test.test_gdb.PyBtTests)
Verify that "py-bt" indicates threads that are waiting for the GIL
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/work/cpython/cpython/Lib/test/test_gdb.py", line 851, in test_threads
    self.assertIn('Waiting for the GIL', gdb_output)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 'Waiting for the GIL' not found in 'Breakpoint 1 at 0x744390: file Python/bltinmodule.c, line 1196.\n[Thread debugging using libthread_db enabled]\nUsing host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".\n[New Thread 0x7ffff40dc700 (LWP 30738)]\n[New Thread 0x7ffff30c5700 (LWP 30739)]\n[New Thread 0x7ffff20ae700 (LWP 30740)]\n[New Thread 0x7ffff1097700 (LWP 30741)]\n\nThread 1 "python" hit Breakpoint 1, builtin_id (self=, v=42) at Python/bltinmodule.c:1196\n1196\t{\n\nThread 5 (Thread 0x7ffff1097700 (LWP 30741) "python"):\n'

----------------------------------------------------------------------

@pablogsal
Copy link
Member Author

Let's land #29267 and then I can remove my changes for the cframe from here

@pablogsal
Copy link
Member Author

@markshannon Rebased, please review again

@markshannon
Copy link
Member

Because cframe is a struct on the C stack, even if the frame-pointer is omitted, it still accessible at a fixed offset from the stack-pointer. I don't know if dwarf supports offsets from rsp, but if it does it, then (in theory) cframe should never be "optimized out", even in optimized builds.

@pablogsal does that sound right to you?

if cframe is None:
return None
frame = PyFramePtr(cframe["current_frame"].dereference())
if frame and not frame.is_optimized_out():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be impossible for frame to be "optimized out" here?

Copy link
Member Author

@pablogsal pablogsal Oct 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if impossible, because optimized out is a value that GDB cannot read, but I agree is certainly very likely never going to be True but I think is still good for safety. You want to remove the check?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you. I'm just guessing here, really.

@pablogsal
Copy link
Member Author

pablogsal commented Oct 28, 2021

Because cframe is a struct on the C stack, even if the frame-pointer is omitted, it still accessible at a fixed offset from the stack-pointer. I don't know if dwarf supports offsets from rsp, but if it does it, then (in theory) cframe should never be "optimized out", even in optimized builds.

@pablogsal does that sound right to you?

That's sadly not true, is optimized out in some of the builds with -O2/O3, including the address sanitizer builds:

❯ gdb --args ./python example.py
(gdb) b builtin_id
Breakpoint 1 at 0x7062c0: file Python/bltinmodule.c, line 1197.
(gdb) r
(gdb)
#4  0x00005555556b839e in _PyEval_EvalFrameDefault (tstate=<optimized out>,
(gdb) p cframe
$1 = <optimized out>
(gdb) p frame
$2 = <optimized out>

@pablogsal
Copy link
Member Author

@markshannon I have tried with several gcc/gdb versions and all have the same behaviour I showed in the previous comment once you use -O3 and most of them with -O2.

@markshannon
Copy link
Member

@markshannon I have tried with several gcc/gdb versions and all have the same behaviour I showed in the previous comment once you use -O3 and most of them with -O2.

Oh well. Let's just do the best we can, then.

@pablogsal
Copy link
Member Author

pablogsal commented Oct 28, 2021

Oh well. Let's just do the best we can, then.

We could mark stuff as volatile but since we have the frame in the current cframe this is going to possible affect performance. Basically, we would need a redundant local that is marked as volatile or that is surrounded with pragmas for -O0.

@pablogsal
Copy link
Member Author

@markshannon I am not super fond of this idea, but I am curious to know what you think

@pablogsal pablogsal requested a review from markshannon October 31, 2021 22:23
@pablogsal pablogsal merged commit f4c0348 into python:main Nov 9, 2021
@pablogsal pablogsal deleted the bpo-45637 branch November 9, 2021 11:19
thatbirdguythatuknownot added a commit to thatbirdguythatuknownot/cpython that referenced this pull request Nov 9, 2021
thatbirdguythatuknownot added a commit to thatbirdguythatuknownot/cpython that referenced this pull request Nov 9, 2021
remykarem pushed a commit to remykarem/cpython that referenced this pull request Dec 7, 2021
remykarem pushed a commit to remykarem/cpython that referenced this pull request Jan 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants