@@ -571,6 +571,53 @@ def usage(self):
571571 print (" rb-stack-trace # Show backtrace for current fiber/thread" )
572572 print (" rb-stack-trace --values # Show backtrace with stack VALUEs" )
573573
574+ def _get_current_execution_context (self ):
575+ """Get the current execution context from the running thread.
576+
577+ Tries multiple approaches in order of preference:
578+ 1. ruby_current_ec - TLS variable (works in GDB, some LLDB)
579+ 2. rb_current_ec_noinline() - function call (works in most cases)
580+ 3. rb_current_ec() - macOS-specific function
581+
582+ Returns:
583+ Execution context value, or None if not available
584+ """
585+ # Try ruby_current_ec variable first
586+ try :
587+ ec = debugger .parse_and_eval ('ruby_current_ec' )
588+ if ec is not None and int (ec ) != 0 :
589+ print (f"DEBUG: Got execution context from ruby_current_ec: { ec } " , file = sys .stderr )
590+ return ec
591+ else :
592+ print (f"DEBUG: ruby_current_ec returned null/zero: { ec } " , file = sys .stderr )
593+ except debugger .Error as e :
594+ print (f"DEBUG: ruby_current_ec failed: { e } " , file = sys .stderr )
595+
596+ # Fallback to rb_current_ec_noinline() function
597+ try :
598+ ec = debugger .parse_and_eval ('rb_current_ec_noinline()' )
599+ if ec is not None and int (ec ) != 0 :
600+ print (f"DEBUG: Got execution context from rb_current_ec_noinline(): { ec } " , file = sys .stderr )
601+ return ec
602+ else :
603+ print (f"DEBUG: rb_current_ec_noinline() returned null/zero: { ec } " , file = sys .stderr )
604+ except debugger .Error as e :
605+ print (f"DEBUG: rb_current_ec_noinline() failed: { e } " , file = sys .stderr )
606+
607+ # Last resort: rb_current_ec() (macOS-specific)
608+ try :
609+ ec = debugger .parse_and_eval ('rb_current_ec()' )
610+ if ec is not None and int (ec ) != 0 :
611+ print (f"DEBUG: Got execution context from rb_current_ec(): { ec } " , file = sys .stderr )
612+ return ec
613+ else :
614+ print (f"DEBUG: rb_current_ec() returned null/zero: { ec } " , file = sys .stderr )
615+ except debugger .Error as e :
616+ print (f"DEBUG: rb_current_ec() failed: { e } " , file = sys .stderr )
617+
618+ print ("DEBUG: All methods to get execution context failed" , file = sys .stderr )
619+ return None
620+
574621 def invoke (self , arg , from_tty ):
575622 """Execute the stack trace command."""
576623 try :
@@ -602,38 +649,13 @@ def invoke(self, arg, from_tty):
602649 print ()
603650
604651 try :
605- # Get current execution context from the running thread
606- # The approach depends on the debugger:
607- # - GDB can access thread-local variable ruby_current_ec directly
608- # - LLDB cannot access TLS variables, must use rb_current_ec_noinline()
609- ec = None
610-
611- if debugger .DEBUGGER_NAME == 'gdb' :
612- # GDB: Try direct TLS variable access first (faster)
613- try :
614- ec = debugger .parse_and_eval ('ruby_current_ec' )
615- except debugger .Error :
616- # Fallback to function call
617- try :
618- ec = debugger .parse_and_eval ('rb_current_ec_noinline()' )
619- except debugger .Error :
620- pass
621- else :
622- # LLDB: Must use function call (cannot access TLS variables)
623- try :
624- ec = debugger .parse_and_eval ('rb_current_ec_noinline()' )
625- except debugger .Error :
626- # Fallback attempts for macOS or other platforms
627- try :
628- ec = debugger .parse_and_eval ('rb_current_ec()' )
629- except debugger .Error :
630- pass
652+ ec = self ._get_current_execution_context ()
631653
632- if ec is None or int ( ec ) == 0 :
654+ if ec is None :
633655 print ("Error: No execution context available" )
634656 print ("Either select a fiber with 'rb-fiber-switch' or ensure Ruby is running" )
635657 print ("\n Troubleshooting:" )
636- print (" - Check if Ruby symbols are loaded: image lookup -n rb_current_ec_noinline " )
658+ print (" - Check if Ruby symbols are loaded" )
637659 print (" - Ensure the process is stopped at a Ruby frame" )
638660 return
639661
0 commit comments