@@ -2834,6 +2834,11 @@ private final void execute(PageSource ps, boolean throwExcpetion, boolean onlyTo
28342834 if (fdEnabled ) {
28352835 FDSignal .signal (pe , false );
28362836 }
2837+ // External debugger extension - uncaught exception
2838+ if (debuggerFrames != null ) {
2839+ DebuggerListener debugListener = DebuggerRegistry .getListener ();
2840+ debuggerNotifyException (debugListener , pe , false );
2841+ }
28372842 listener .onError (this , pe ); // call Application.onError()
28382843 }
28392844 else log (false );
@@ -3435,27 +3440,10 @@ public void _setCatch(PageException pe, String name, boolean caught, boolean sto
34353440 if (fdEnabled ) {
34363441 FDSignal .signal (pe , caught );
34373442 }
3438- // External debugger (luceedebug) - frames are still intact at this point
3443+ // External debugger extension - frames are still intact at this point
34393444 if (debuggerFrames != null ) {
34403445 DebuggerListener listener = DebuggerRegistry .getListener ();
3441- if (listener != null && listener .isClientConnected () && listener .onException (this , pe , caught )) {
3442- // Get file/line from exception for debugger display
3443- String file = null ;
3444- int line = 0 ;
3445- if (pe instanceof PageExceptionImpl ) {
3446- PageExceptionImpl pei = (PageExceptionImpl ) pe ;
3447- file = pei .getFile (getConfig ());
3448- try {
3449- String lineStr = pei .getLine (getConfig ());
3450- if (lineStr != null && !lineStr .isEmpty ()) {
3451- line = Integer .parseInt (lineStr );
3452- }
3453- }
3454- catch (NumberFormatException ignored ) {}
3455- }
3456- String label = caught ? "Caught exception: " : "Uncaught exception: " ;
3457- debuggerSuspend (file , line , label + pe .getClass ().getSimpleName ());
3458- }
3446+ debuggerNotifyException (listener , pe , caught );
34593447 }
34603448 }
34613449 // boolean outer = exception != null && exception == pe;
@@ -3592,22 +3580,13 @@ public void popDebuggerFrame() {
35923580
35933581 /**
35943582 * Get all debugger frames for the current call stack. Returns null if debugger is not enabled.
3583+ * Called via reflection by the debugger extension.
35953584 */
35963585 public DebuggerFrame [] getDebuggerFrames () {
35973586 if (debuggerFrames == null ) return null ;
35983587 return debuggerFrames .toArray (new DebuggerFrame [0 ]);
35993588 }
36003589
3601- /**
3602- * Update the line number of the topmost debugger frame. Called on each CFML line when
3603- * stepping/breakpoints are active.
3604- */
3605- public void setDebuggerLine (int line ) {
3606- if (debuggerFrames != null && !debuggerFrames .isEmpty ()) {
3607- debuggerFrames .getLast ().setLine (line );
3608- }
3609- }
3610-
36113590 /**
36123591 * Get the topmost debugger frame, or null if none.
36133592 */
@@ -3616,6 +3595,29 @@ public DebuggerFrame getTopmostDebuggerFrame() {
36163595 return debuggerFrames .getLast ();
36173596 }
36183597
3598+ /**
3599+ * Notify the debugger listener of an exception and suspend if requested.
3600+ */
3601+ private void debuggerNotifyException (DebuggerListener listener , PageException pe , boolean caught ) {
3602+ if (listener == null || !listener .isClientConnected () || !listener .onException (this , pe , caught )) return ;
3603+ String file = null ;
3604+ int line = 0 ;
3605+ if (pe instanceof PageExceptionImpl ) {
3606+ PageExceptionImpl pei = (PageExceptionImpl ) pe ;
3607+ file = pei .getFile (getConfig ());
3608+ try {
3609+ String lineStr = pei .getLine (getConfig ());
3610+ if (lineStr != null && !lineStr .isEmpty ()) {
3611+ line = Integer .parseInt (lineStr );
3612+ }
3613+ }
3614+ catch (NumberFormatException ignored ) {
3615+ }
3616+ }
3617+ String label = caught ? "Caught exception: " : "Uncaught exception: " ;
3618+ debuggerSuspend (file , line , label + pe .getClass ().getSimpleName ());
3619+ }
3620+
36193621 // Debugger suspension support
36203622 private volatile boolean debuggerSuspended = false ;
36213623 private volatile String debuggerSuspendLabel = null ;
@@ -3687,13 +3689,18 @@ private void debuggerSuspendImpl(String file, int line, String label) {
36873689 synchronized (debuggerSuspendLock ) {
36883690 while (debuggerSuspended ) {
36893691 try {
3690- debuggerSuspendLock .wait ();
3692+ debuggerSuspendLock .wait (5000 );
36913693 }
36923694 catch (InterruptedException e ) {
36933695 Thread .currentThread ().interrupt ();
36943696 LogUtil .log (this , "application" , "debugger" , e , Log .LEVEL_WARN );
36953697 break ;
36963698 }
3699+ // Auto-resume if debugger disconnected while suspended
3700+ if (debuggerSuspended && !DebuggerRegistry .isClientConnected ()) {
3701+ LogUtil .log (Log .LEVEL_WARN , "application" , "Debugger disconnected while thread suspended - auto-resuming" );
3702+ debuggerSuspended = false ;
3703+ }
36973704 }
36983705 }
36993706 debuggerTotalSuspendedNanos += System .nanoTime () - debuggerSuspendStartNano ;
@@ -3707,6 +3714,7 @@ private void debuggerSuspendImpl(String file, int line, String label) {
37073714
37083715 /**
37093716 * Resume execution after debugger suspension.
3717+ * Called via reflection by the debugger extension.
37103718 */
37113719 public void debuggerResume () {
37123720 debuggerSuspended = false ;
@@ -3717,25 +3725,20 @@ public void debuggerResume() {
37173725
37183726 /**
37193727 * Check if this PageContext is currently suspended.
3728+ * Available for debugger extensions via reflection.
37203729 */
37213730 public boolean isDebuggerSuspended () {
37223731 return debuggerSuspended ;
37233732 }
37243733
37253734 /**
37263735 * Get the label of the current suspension point, or null.
3736+ * Available for debugger extensions via reflection.
37273737 */
37283738 public String getDebuggerSuspendLabel () {
37293739 return debuggerSuspendLabel ;
37303740 }
37313741
3732- /**
3733- * Get total time spent suspended (for adjusting request timeouts).
3734- */
3735- public long getDebuggerTotalSuspendedNanos () {
3736- return debuggerTotalSuspendedNanos ;
3737- }
3738-
37393742 /**
37403743 * Get total time spent suspended in milliseconds, including current suspend if active. Used for
37413744 * adjusting request timeout calculations.
0 commit comments