@@ -2664,7 +2664,7 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self,
26642664@critical_section
26652665_remote_debugging.RemoteUnwinder.get_stack_trace
26662666
2667- Returns stack traces for all interpreters and threads in target process.
2667+ Returns stack traces for all interpreters and threads in process.
26682668
26692669Each element in the returned list is a tuple of (interpreter_id, thread_list), where:
26702670- interpreter_id is the interpreter identifier
@@ -2708,7 +2708,7 @@ The threads returned depend on the initialization parameters:
27082708
27092709static PyObject *
27102710_remote_debugging_RemoteUnwinder_get_stack_trace_impl (RemoteUnwinderObject * self )
2711- /*[clinic end generated code: output=666192b90c69d567 input=b5b7f2e7e2a91318 ]*/
2711+ /*[clinic end generated code: output=666192b90c69d567 input=bcff01c73cccc1c0 ]*/
27122712{
27132713 PyObject * result = PyList_New (0 );
27142714 if (!result ) {
@@ -2734,11 +2734,114 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self
27342734 int64_t interpreter_id = GET_MEMBER (int64_t , interp_state_buffer ,
27352735 self -> debug_offsets .interpreter_state .id );
27362736
2737- if (process_interpreter_threads (self , current_interpreter , result , interpreter_id ) < 0 ) {
2737+ // Get code object generation from buffer
2738+ uint64_t code_object_generation = GET_MEMBER (uint64_t , interp_state_buffer ,
2739+ self -> debug_offsets .interpreter_state .code_object_generation );
2740+
2741+ if (code_object_generation != self -> code_object_generation ) {
2742+ self -> code_object_generation = code_object_generation ;
2743+ _Py_hashtable_clear (self -> code_object_cache );
2744+ }
2745+
2746+ #ifdef Py_GIL_DISABLED
2747+ // Check TLBC generation and invalidate cache if needed
2748+ uint32_t current_tlbc_generation = GET_MEMBER (uint32_t , interp_state_buffer ,
2749+ self -> debug_offsets .interpreter_state .tlbc_generation );
2750+ if (current_tlbc_generation != self -> tlbc_generation ) {
2751+ self -> tlbc_generation = current_tlbc_generation ;
2752+ _Py_hashtable_clear (self -> tlbc_cache );
2753+ }
2754+ #endif
2755+
2756+ // Create a list to hold threads for this interpreter
2757+ PyObject * interpreter_threads = PyList_New (0 );
2758+ if (!interpreter_threads ) {
2759+ set_exception_cause (self , PyExc_MemoryError , "Failed to create interpreter threads list" );
27382760 Py_CLEAR (result );
27392761 goto exit ;
27402762 }
27412763
2764+ uintptr_t current_tstate ;
2765+ if (self -> only_active_thread ) {
2766+ // Find the GIL holder for THIS interpreter
2767+ int gil_locked = GET_MEMBER (int , interp_state_buffer ,
2768+ self -> debug_offsets .interpreter_state .gil_runtime_state_locked );
2769+
2770+ if (!gil_locked ) {
2771+ // This interpreter's GIL is not locked, skip it
2772+ Py_DECREF (interpreter_threads );
2773+ goto next_interpreter ;
2774+ }
2775+
2776+ // Get the GIL holder for this interpreter
2777+ current_tstate = (uintptr_t )GET_MEMBER (PyThreadState * , interp_state_buffer ,
2778+ self -> debug_offsets .interpreter_state .gil_runtime_state_holder );
2779+ } else if (self -> tstate_addr == 0 ) {
2780+ // Get all threads for this interpreter
2781+ current_tstate = GET_MEMBER (uintptr_t , interp_state_buffer ,
2782+ self -> debug_offsets .interpreter_state .threads_head );
2783+ } else {
2784+ // Target specific thread (only process first interpreter)
2785+ current_tstate = self -> tstate_addr ;
2786+ }
2787+
2788+ while (current_tstate != 0 ) {
2789+ PyObject * frame_info = unwind_stack_for_thread (self , & current_tstate );
2790+ if (!frame_info ) {
2791+ Py_DECREF (interpreter_threads );
2792+ set_exception_cause (self , PyExc_RuntimeError , "Failed to unwind stack for thread" );
2793+ Py_CLEAR (result );
2794+ goto exit ;
2795+ }
2796+
2797+ if (PyList_Append (interpreter_threads , frame_info ) == -1 ) {
2798+ Py_DECREF (frame_info );
2799+ Py_DECREF (interpreter_threads );
2800+ set_exception_cause (self , PyExc_RuntimeError , "Failed to append thread frame info" );
2801+ Py_CLEAR (result );
2802+ goto exit ;
2803+ }
2804+ Py_DECREF (frame_info );
2805+
2806+ // If targeting specific thread or only active thread, process just one
2807+ if (self -> tstate_addr || self -> only_active_thread ) {
2808+ break ;
2809+ }
2810+ }
2811+
2812+ // Create the InterpreterInfo StructSequence
2813+ RemoteDebuggingState * state = RemoteDebugging_GetStateFromObject ((PyObject * )self );
2814+ PyObject * interpreter_info = PyStructSequence_New (state -> InterpreterInfo_Type );
2815+ if (!interpreter_info ) {
2816+ Py_DECREF (interpreter_threads );
2817+ set_exception_cause (self , PyExc_MemoryError , "Failed to create InterpreterInfo" );
2818+ Py_CLEAR (result );
2819+ goto exit ;
2820+ }
2821+
2822+ PyObject * interp_id = PyLong_FromLongLong (interpreter_id );
2823+ if (!interp_id ) {
2824+ Py_DECREF (interpreter_threads );
2825+ Py_DECREF (interpreter_info );
2826+ set_exception_cause (self , PyExc_MemoryError , "Failed to create interpreter ID" );
2827+ Py_CLEAR (result );
2828+ goto exit ;
2829+ }
2830+
2831+ PyStructSequence_SetItem (interpreter_info , 0 , interp_id ); // steals reference
2832+ PyStructSequence_SetItem (interpreter_info , 1 , interpreter_threads ); // steals reference
2833+
2834+ // Add this interpreter to the result list
2835+ if (PyList_Append (result , interpreter_info ) == -1 ) {
2836+ Py_DECREF (interpreter_info );
2837+ set_exception_cause (self , PyExc_RuntimeError , "Failed to append interpreter info" );
2838+ Py_CLEAR (result );
2839+ goto exit ;
2840+ }
2841+ Py_DECREF (interpreter_info );
2842+
2843+ next_interpreter :
2844+
27422845 // Get the next interpreter address
27432846 current_interpreter = GET_MEMBER (uintptr_t , interp_state_buffer ,
27442847 self -> debug_offsets .interpreter_state .next );
0 commit comments