Skip to content

Commit 1118285

Browse files
committed
Rework to share code, also catch calls into native code in top frames
1 parent 103835e commit 1118285

File tree

1 file changed

+38
-31
lines changed

1 file changed

+38
-31
lines changed

Modules/_remote_debugging_module.c

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,46 +2486,53 @@ process_frame_chain(
24862486
return -1;
24872487
}
24882488
}
2489-
2489+
if (frame == NULL && PyList_GET_SIZE(frame_info) == 0) {
2490+
// If the first frame is missing, the chain is broken:
2491+
const char *e = "Failed to parse initial frame in chain";
2492+
PyErr_SetString(PyExc_RuntimeError, e);
2493+
return -1;
2494+
}
2495+
_Py_DECLARE_STR(native, "<native>");
2496+
_Py_DECLARE_STR(gc, "<GC>");
2497+
PyObject *extra_frame = NULL;
2498+
// This frame kicked off the current GC collection:
24902499
if (unwinder->gc && frame_addr == gc_frame) {
2491-
_Py_DECLARE_STR(gc, "<GC>");
2500+
extra_frame = &_Py_STR(gc);
2501+
}
2502+
// Otherwise, check for native frames to insert:
2503+
else if (unwinder->native) {
2504+
// Topmost frame spilled its stack pointer for a native call:
2505+
if (PyList_GET_SIZE(frame_info) == 0 &&
2506+
GET_MEMBER(uintptr_t, frame_addr, unwinder->debug_offsets.interpreter_frame.stackpointer))
2507+
{
2508+
extra_frame = &_Py_STR(native);
2509+
}
2510+
// Or, we've reached an interpreter trampoline frame:
2511+
else if (frame == NULL &&
2512+
// Bottommost frame is always native, so skip that one:
2513+
next_frame_addr &&
2514+
// If the next frame will be reported as a GC frame, then
2515+
// don't add an extra native frame below it:
2516+
!(unwinder->gc && next_frame_addr == gc_frame))
2517+
{
2518+
extra_frame = &_Py_STR(native);
2519+
}
2520+
}
2521+
if (extra_frame) {
24922522
// Use "~" as file and 0 as line, since that's what pstats uses:
2493-
PyObject *gc_info = make_frame_info(unwinder, _Py_LATIN1_CHR('~'),
2494-
_PyLong_GetZero(), &_Py_STR(gc));
2495-
if (gc_info == NULL) {
2523+
PyObject *extra_frame_info = make_frame_info(
2524+
unwinder, _Py_LATIN1_CHR('~'), _PyLong_GetZero(), extra_frame);
2525+
if (extra_frame_info == NULL) {
24962526
return -1;
24972527
}
2498-
int error = PyList_Append(frame_info, gc_info);
2499-
Py_DECREF(gc_info);
2528+
int error = PyList_Append(frame_info, extra_frame_info);
2529+
Py_DECREF(extra_frame_info);
25002530
if (error) {
2501-
const char *e = "Failed to append GC to frame info list";
2531+
const char *e = "Failed to append extra frame to frame info list";
25022532
set_exception_cause(unwinder, PyExc_RuntimeError, e);
25032533
return -1;
25042534
}
25052535
}
2506-
if (frame == NULL) {
2507-
if (PyList_GET_SIZE(frame_info) == 0) {
2508-
// If the first frame is missing, the chain is broken:
2509-
const char *e = "Failed to parse initial frame in chain";
2510-
PyErr_SetString(PyExc_RuntimeError, e);
2511-
return -1;
2512-
}
2513-
if (unwinder->native &&
2514-
// The last frame is always native, so skip that one:
2515-
next_frame_addr &&
2516-
// If the next frame will be reported as a GC frame, then don't
2517-
// add an extra native frame below it:
2518-
!(unwinder->gc && next_frame_addr == gc_frame))
2519-
{
2520-
_Py_DECLARE_STR(native, "<native>");
2521-
// Use "~" as file and 0 as line, since that's what pstats uses:
2522-
frame = make_frame_info(unwinder, _Py_LATIN1_CHR('~'),
2523-
_PyLong_GetZero(), &_Py_STR(native));
2524-
if (frame == NULL) {
2525-
return -1;
2526-
}
2527-
}
2528-
}
25292536
if (frame) {
25302537
if (prev_frame_addr && frame_addr != prev_frame_addr) {
25312538
const char *f = "Broken frame chain: expected frame at 0x%lx, got 0x%lx";

0 commit comments

Comments
 (0)