1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-06 17:26:01 +02:00

More implementation.

This commit is contained in:
Mikhail Khodjaiants 2002-08-07 21:51:10 +00:00
parent 619ee91fb2
commit 0fecb04151
6 changed files with 1480 additions and 60 deletions

View file

@ -6,6 +6,8 @@
package org.eclipse.cdt.debug.core;
import org.eclipse.core.runtime.IAdaptable;
/**
*
* Represents the current state of debug element.
@ -27,5 +29,17 @@ public interface IState
public static final int TERMINATED = 10;
public static final int CORE_DUMP_FILE = 11;
int getCurrentState();
/**
* Returns the identifier of the current state.
*
* @return the identifier of the current state
*/
int getCurrentStateId();
/**
* Returns the info object associated with the current state.
*
* @return the info object associated with the current state
*/
Object getCurrentStateInfo();
}

View file

@ -0,0 +1,149 @@
/*
*(c) Copyright QNX Software Systems Ltd. 2002.
* All Rights Reserved.
*
*/
package org.eclipse.cdt.debug.internal.core;
import org.eclipse.cdt.debug.core.cdi.ICSession;
/**
*
* Provides the convenience access methods to the configuration
* parameters of the debug session.
*
* @since Aug 6, 2002
*/
public class CDebugConfiguration
{
private ICSession fSession;
/**
* Constructor for CDebugConfiguration.
*/
public CDebugConfiguration( ICSession session )
{
fSession = session;
}
/**
* Returns whether this session supports termination.
*
* @return whether this session supports termination
*/
public boolean supportsTerminate()
{
return true;
}
/**
* Returns whether this session supports disconnecting.
*
* @return whether this session supports disconnecting
*/
public boolean supportsDisconnect()
{
return true;
}
/**
* Returns whether this session supports suspend/resume.
*
* @return whether this session supports suspend/resume
*/
public boolean supportsSuspendResume()
{
return true;
}
/**
* Returns whether this session supports restarting.
*
* @return whether this session supports restarting
*/
public boolean supportsRestart()
{
return true;
}
/**
* Returns whether this session supports stepping.
*
* @return whether this session supports stepping
*/
public boolean supportsStepping()
{
return true;
}
/**
* Returns whether this session supports instruction stepping.
*
* @return whether this session supports instruction stepping
*/
public boolean supportsInstructionStepping()
{
return true;
}
/**
* Returns whether this session supports breakpoints.
*
* @return whether this session supports breakpoints
*/
public boolean supportsBreakpoints()
{
return true;
}
/**
* Returns whether this session supports registers.
*
* @return whether this session supports registers
*/
public boolean supportsRegisters()
{
return true;
}
/**
* Returns whether this session supports register modification.
*
* @return whether this session supports registers modification
*/
public boolean supportsRegisterModification()
{
return true;
}
/**
* Returns whether this session supports memory retrieval.
*
* @return whether this session supports memory retrieval
*/
public boolean supportsMemoryRetrieval()
{
return true;
}
/**
* Returns whether this session supports memory modification.
*
* @return whether this session supports memory modification
*/
public boolean supportsMemoryModification()
{
return true;
}
/**
* Returns whether this session supports expression evaluation.
*
* @return whether this session supports expression evaluation
*/
public boolean supportsExpressionEvaluation()
{
return true;
}
}

View file

@ -7,6 +7,7 @@ package org.eclipse.cdt.debug.internal.core;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.cdt.debug.core.CDebugModel;
@ -46,6 +47,7 @@ import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.IStep;
import org.eclipse.debug.core.model.IThread;
/**
@ -58,7 +60,6 @@ public class CDebugTarget extends CDebugElement
implements IDebugTarget,
ICEventListener,
IRestart,
IInstructionStep,
IFormattedMemoryRetrieval,
IState,
ILaunchListener
@ -76,7 +77,7 @@ public class CDebugTarget extends CDebugElement
private IProcess fProcess;
/**
* Underlying CDI target.
* The underlying CDI target.
*/
private ICTarget fCDITarget;
@ -115,6 +116,11 @@ public class CDebugTarget extends CDebugElement
*/
private ILaunch fLaunch;
/**
* The debug configuration of this session
*/
private CDebugConfiguration fConfig;
/**
* Whether terminate is supported.
*/
@ -125,6 +131,16 @@ public class CDebugTarget extends CDebugElement
*/
private boolean fSupportsDisconnect;
/**
* The current state identifier.
*/
private int fCurrentStateId = IState.UNKNOWN;
/**
* The current state info.
*/
private Object fCurrentStateInfo = null;
/**
* Constructor for CDebugTarget.
* @param target
@ -143,6 +159,9 @@ public class CDebugTarget extends CDebugElement
setName( name );
setProcess( process );
setCDITarget( cdiTarget );
fConfig = new CDebugConfiguration( cdiTarget.getSession() );
fSupportsTerminate = allowsTerminate & fConfig.supportsTerminate();
fSupportsDisconnect = allowsDisconnect & fConfig.supportsDisconnect();
setThreadList( new ArrayList( 5 ) );
initialize();
DebugPlugin.getDefault().getLaunchManager().addLaunchListener( this );
@ -299,7 +318,7 @@ public class CDebugTarget extends CDebugElement
*/
public boolean canTerminate()
{
return false;
return supportsTerminate() && isAvailable();
}
/* (non-Javadoc)
@ -370,6 +389,23 @@ public class CDebugTarget extends CDebugElement
*/
public void resume() throws DebugException
{
if ( !isSuspended() )
{
return;
}
try
{
setSuspended( false );
getCDITarget().resume();
resumeThreads();
fireResumeEvent( DebugEvent.CLIENT_REQUEST );
}
catch( CDIException e )
{
setSuspended( true );
fireSuspendEvent( DebugEvent.CLIENT_REQUEST );
targetRequestFailed( MessageFormat.format( "{0} occurred resuming target.", new String[] { e.toString() } ), e );
}
}
/* (non-Javadoc)
@ -404,6 +440,13 @@ public class CDebugTarget extends CDebugElement
{
}
/**
* Notifies threads that they have been resumed
*/
protected void resumeThreads()
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(IBreakpoint)
*/
@ -425,12 +468,32 @@ public class CDebugTarget extends CDebugElement
{
}
/**
* Returns whether this debug target supports disconnecting.
*
* @return whether this debug target supports disconnecting
*/
protected boolean supportsDisconnect()
{
return fConfig.supportsDisconnect();
}
/**
* Returns whether this debug target supports termination.
*
* @return whether this debug target supports termination
*/
protected boolean supportsTerminate()
{
return fConfig.supportsTerminate();
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
*/
public boolean canDisconnect()
{
return false;
return supportsDisconnect() && !isDisconnected();
}
/* (non-Javadoc)
@ -438,6 +501,26 @@ public class CDebugTarget extends CDebugElement
*/
public void disconnect() throws DebugException
{
if ( isDisconnected() )
{
// already done
return;
}
if ( !canDisconnect() )
{
notSupported( "Session does not support \'disconnect\'" );
}
try
{
getCDITarget().disconnect();
disconnected();
}
catch( CDIException e )
{
targetRequestFailed( MessageFormat.format( "{0} ocurred disconnecting from target.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
@ -530,6 +613,8 @@ public class CDebugTarget extends CDebugElement
return this;
if ( adapter.equals( ICTarget.class ) )
return fCDITarget;
if ( adapter.equals( IState.class ) )
return this;
return super.getAdapter( adapter );
}
@ -623,7 +708,7 @@ public class CDebugTarget extends CDebugElement
*/
public boolean canRestart()
{
return false;
return fConfig.supportsRestart() && isSuspended() && isAvailable();
}
/* (non-Javadoc)
@ -631,35 +716,27 @@ public class CDebugTarget extends CDebugElement
*/
public void restart() throws DebugException
{
if ( !canRestart() )
{
return;
}
try
{
getCDITarget().restart();
restarted();
}
catch( CDIException e )
{
targetRequestFailed( MessageFormat.format( "{0} ocurred restarting the target.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#canStepIntoInstruction()
/**
* Updates the state of this target for restarting.
*
*/
public boolean canStepIntoInstruction()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#canStepOverInstruction()
*/
public boolean canStepOverInstruction()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#stepIntoInstruction()
*/
public void stepIntoInstruction() throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#stepOverInstruction()
*/
public void stepOverInstruction() throws DebugException
protected void restarted()
{
}
@ -704,7 +781,7 @@ public class CDebugTarget extends CDebugElement
*/
public boolean isAvailable()
{
return false;
return !( isTerminated() || isTerminating() || isDisconnected() );
}
/**
@ -754,8 +831,8 @@ public class CDebugTarget extends CDebugElement
}
/**
* Updates the state of this target for disconnection
* from the VM.
* Updates the state of this target for disconnection.
*
*/
protected void disconnected()
{
@ -788,6 +865,13 @@ public class CDebugTarget extends CDebugElement
*/
protected void removeAllThreads()
{
Iterator itr = getThreadList().iterator();
setThreadList( new ArrayList( 0 ) );
while( itr.hasNext() )
{
CThread thread = (CThread)itr.next();
thread.terminated();
}
}
/**
@ -863,7 +947,9 @@ public class CDebugTarget extends CDebugElement
private void handleSuspendedEvent( ICSuspendedEvent event )
{
setSuspended( true );
setCurrentStateId( IState.SUSPENDED );
ICSessionObject reason = event.getReason();
setCurrentStateInfo( reason );
if ( reason instanceof ICEndSteppingRange )
{
handleEndSteppingRange( (ICEndSteppingRange)reason );
@ -881,6 +967,8 @@ public class CDebugTarget extends CDebugElement
private void handleResumedEvent( ICResumedEvent event )
{
setSuspended( false );
setCurrentStateId( IState.RUNNING );
setCurrentStateInfo( null );
fireResumeEvent( DebugEvent.UNSPECIFIED );
}
@ -901,16 +989,22 @@ public class CDebugTarget extends CDebugElement
private void handleExitedEvent( ICExitedEvent event )
{
setCurrentStateId( IState.EXITED );
setCurrentStateInfo( event.getExitInfo() );
fireChangeEvent( DebugEvent.STATE );
}
private void handleTerminatedEvent( ICTerminatedEvent event )
{
setCurrentStateId( IState.TERMINATED );
setCurrentStateInfo( null );
terminated();
}
private void handleDisconnectedEvent( ICDisconnectedEvent event )
{
setCurrentStateId( IState.DISCONNECTED );
setCurrentStateInfo( null );
disconnected();
}
@ -928,6 +1022,8 @@ public class CDebugTarget extends CDebugElement
private void handleSteppingEvent( ICSteppingEvent event )
{
setCurrentStateId( IState.STEPPING );
setCurrentStateInfo( null );
}
private void handleThreadCreatedEvent( ICCreatedEvent event )
@ -976,10 +1072,38 @@ public class CDebugTarget extends CDebugElement
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IState#getCurrentState()
* @see org.eclipse.cdt.debug.core.IState#getCurrentStateId()
*/
public int getCurrentState()
public int getCurrentStateId()
{
return IState.UNKNOWN;
return fCurrentStateId;
}
/**
* Sets the current state identifier.
*
* @param id the identifier
*/
private void setCurrentStateId( int id )
{
fCurrentStateId = id;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IState#getCurrentStateInfo()
*/
public Object getCurrentStateInfo()
{
return fCurrentStateInfo;
}
/**
* Sets the info object of the current state.
*
* @param id the info object
*/
private void setCurrentStateInfo( Object info )
{
fCurrentStateInfo = info;
}
}

View file

@ -0,0 +1,112 @@
/*
*(c) Copyright QNX Software Systems Ltd. 2002.
* All Rights Reserved.
*
*/
package org.eclipse.cdt.debug.internal.core;
import org.eclipse.cdt.debug.core.cdi.event.ICEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICEventListener;
import org.eclipse.cdt.debug.core.cdi.model.ICVariable;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IValue;
import org.eclipse.debug.core.model.IVariable;
/**
*
* Proxy to a local variaable on the target.
*
* @since Aug 7, 2002
*/
public class CLocalVariable extends CDebugElement
implements IVariable,
ICEventListener
{
/**
* Constructor for CLocalVariable.
* @param target
*/
public CLocalVariable( CStackFrame stackFrame, ICVariable cdiVariable )
{
super( (CDebugTarget)stackFrame.getDebugTarget() );
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IVariable#getValue()
*/
public IValue getValue() throws DebugException
{
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IVariable#getName()
*/
public String getName() throws DebugException
{
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IVariable#getReferenceTypeName()
*/
public String getReferenceTypeName() throws DebugException
{
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IVariable#hasValueChanged()
*/
public boolean hasValueChanged() throws DebugException
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.cdi.event.ICEventListener#handleDebugEvent(ICEvent)
*/
public void handleDebugEvent( ICEvent event )
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValueModification#setValue(String)
*/
public void setValue( String expression ) throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValueModification#setValue(IValue)
*/
public void setValue( IValue value ) throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValueModification#supportsValueModification()
*/
public boolean supportsValueModification()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValueModification#verifyValue(String)
*/
public boolean verifyValue( String expression ) throws DebugException
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValueModification#verifyValue(IValue)
*/
public boolean verifyValue( IValue value ) throws DebugException
{
return false;
}
}

View file

@ -0,0 +1,405 @@
/*
*(c) Copyright QNX Software Systems Ltd. 2002.
* All Rights Reserved.
*
*/
package org.eclipse.cdt.debug.internal.core;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.cdt.debug.core.cdi.CDIException;
import org.eclipse.cdt.debug.core.cdi.event.ICEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICEventListener;
import org.eclipse.cdt.debug.core.cdi.model.ICArgument;
import org.eclipse.cdt.debug.core.cdi.model.ICStackFrame;
import org.eclipse.cdt.debug.core.cdi.model.ICVariable;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IRegisterGroup;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.core.model.IVariable;
/**
*
* Proxy to a stack frame on the target.
*
* @since Aug 7, 2002
*/
public class CStackFrame extends CDebugElement
implements IStackFrame,
ICEventListener
{
/**
* Underlying CDI stack frame.
*/
private ICStackFrame fCDIStackFrame;
/**
* Containing thread.
*/
private CThread fThread;
/**
* Visible variables.
*/
private List fVariables;
/**
* Whether the variables need refreshing
*/
private boolean fRefreshVariables = true;
/**
* Constructor for CStackFrame.
* @param target
*/
public CStackFrame( CThread thread, ICStackFrame cdiFrame )
{
super( (CDebugTarget)thread.getDebugTarget() );
fCDIStackFrame = cdiFrame;
setThread( thread );
getCDISession().getEventManager().addEventListener( this );
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#getThread()
*/
public IThread getThread()
{
return fThread;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#getVariables()
*/
public IVariable[] getVariables() throws DebugException
{
List list = getVariables0();
return (IVariable[])list.toArray( new IVariable[list.size()] );
}
protected synchronized List getVariables0() throws DebugException
{
if ( fVariables == null )
{
fVariables = new ArrayList();
fVariables.addAll( getCDIArguments() );
fVariables.addAll( getCDILocalVariables() );
}
else if ( fRefreshVariables )
{
updateVariables();
}
fRefreshVariables = false;
return fVariables;
}
/**
* Incrementally updates this stack frames variables.
*
*/
protected void updateVariables() throws DebugException
{
}
/**
* Sets the containing thread.
*
* @param thread the containing thread
*/
protected void setThread( CThread thread )
{
fThread = thread;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#hasVariables()
*/
public boolean hasVariables() throws DebugException
{
return getVariables0().size() > 0;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#getLineNumber()
*/
public int getLineNumber() throws DebugException
{
return 0;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#getCharStart()
*/
public int getCharStart() throws DebugException
{
return 0;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#getCharEnd()
*/
public int getCharEnd() throws DebugException
{
return 0;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#getName()
*/
public String getName() throws DebugException
{
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#getRegisterGroups()
*/
public IRegisterGroup[] getRegisterGroups() throws DebugException
{
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStackFrame#hasRegisterGroups()
*/
public boolean hasRegisterGroups() throws DebugException
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.cdi.event.ICEventListener#handleDebugEvent(ICEvent)
*/
public void handleDebugEvent(ICEvent event)
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStep#canStepInto()
*/
public boolean canStepInto()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStep#canStepOver()
*/
public boolean canStepOver()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStep#canStepReturn()
*/
public boolean canStepReturn()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStep#isStepping()
*/
public boolean isStepping()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStep#stepInto()
*/
public void stepInto() throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStep#stepOver()
*/
public void stepOver() throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IStep#stepReturn()
*/
public void stepReturn() throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ISuspendResume#canResume()
*/
public boolean canResume()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
*/
public boolean canSuspend()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
*/
public boolean isSuspended()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ISuspendResume#resume()
*/
public void resume() throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ISuspendResume#suspend()
*/
public void suspend() throws DebugException
{
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ITerminate#canTerminate()
*/
public boolean canTerminate()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ITerminate#isTerminated()
*/
public boolean isTerminated()
{
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ITerminate#terminate()
*/
public void terminate() throws DebugException
{
}
/**
* Returns the underlying CDI stack frame that this model object is
* a proxy to.
*
* @return the underlying CDI stack frame
*/
protected ICStackFrame getCDIStackFrame()
{
return fCDIStackFrame;
}
/**
* Sets the underlying CDI stack frame. Called by a thread
* when incrementally updating after a step has completed.
*
* @param frame the underlying stack frame
*/
protected void setCDIStackFrame( ICStackFrame frame )
{
}
/**
* The underlying stack frame that existed before the current underlying
* stack frame. Used only so that equality can be checked on stack frame
* after the new one has been set.
*/
protected ICStackFrame getLastCDIStackFrame()
{
return null;
}
/**
* Helper method for computeStackFrames(). For the purposes of detecting if
* an underlying stack frame needs to be disposed, stack frames are equal if
* the frames are equal and the locations are equal.
*/
protected static boolean equalFrame( ICStackFrame frameOne, ICStackFrame frameTwo )
{
return false;
}
protected boolean exists() throws DebugException
{
return ((CThread)getThread()).computeStackFrames().indexOf( this ) != -1;
}
/**
* @see IAdaptable#getAdapter(Class)
*/
public Object getAdapter( Class adapter )
{
if ( adapter == IStackFrame.class )
{
return this;
}
if ( adapter == ICStackFrame.class )
{
return getCDIStackFrame();
}
return super.getAdapter( adapter );
}
protected void dispose()
{
getCDISession().getEventManager().removeEventListener( this );
}
/**
* Retrieves local variables in this stack frame. Returns an empty
* list if there are no local variables.
*
*/
protected List getCDILocalVariables() throws DebugException
{
List list = Collections.EMPTY_LIST;
try
{
ICVariable[] vars = getCDIStackFrame().getLocalVariables();
list = new ArrayList( vars.length );
for ( int i = 0; i < vars.length; ++i )
list.add( new CLocalVariable( this, vars[i] ) );
}
catch( CDIException e )
{
targetRequestFailed( MessageFormat.format( "{0} occurred retrieving local variables", new String[] { e.toString() } ), e );
}
return list;
}
/**
* Retrieves arguments in this stack frame. Returns an empty list
* if there are no arguments.
*
*/
protected List getCDIArguments() throws DebugException
{
List list = Collections.EMPTY_LIST;
try
{
ICArgument[] args = getCDIStackFrame().getArguments();
list = new ArrayList( args.length );
for ( int i = 0; i < args.length; ++i )
list.add( new CLocalVariable( this, args[i] ) );
}
catch( CDIException e )
{
targetRequestFailed( MessageFormat.format( "{0} occurred retrieving arguments", new String[] { e.toString() } ), e );
}
return list;
}
}

View file

@ -6,10 +6,31 @@
package org.eclipse.cdt.debug.internal.core;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.cdt.debug.core.IInstructionStep;
import org.eclipse.cdt.debug.core.IState;
import org.eclipse.cdt.debug.core.cdi.CDIException;
import org.eclipse.cdt.debug.core.cdi.ICBreakpoint;
import org.eclipse.cdt.debug.core.cdi.ICEndSteppingRange;
import org.eclipse.cdt.debug.core.cdi.ICSessionObject;
import org.eclipse.cdt.debug.core.cdi.ICSignal;
import org.eclipse.cdt.debug.core.cdi.event.ICChangedEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICDisconnectedEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICEventListener;
import org.eclipse.cdt.debug.core.cdi.event.ICResumedEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICSteppingEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICSuspendedEvent;
import org.eclipse.cdt.debug.core.cdi.event.ICTerminatedEvent;
import org.eclipse.cdt.debug.core.cdi.model.ICObject;
import org.eclipse.cdt.debug.core.cdi.model.ICStackFrame;
import org.eclipse.cdt.debug.core.cdi.model.ICThread;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IStackFrame;
@ -23,14 +44,47 @@ import org.eclipse.debug.core.model.IThread;
*/
public class CThread extends CDebugElement
implements IThread,
IState,
IState,
IInstructionStep,
ICEventListener
{
/**
* Underlying CDI target.
* Underlying CDI thread.
*/
private ICThread fCDIThread;
/**
* Collection of stack frames
*/
private List fStackFrames;
/**
* Whether running.
*/
private boolean fRunning;
/**
* Whether children need to be refreshed. Set to
* <code>true</code> when stack frames are re-used
* on the next suspend.
*/
private boolean fRefreshChildren = true;
/**
* The current state identifier.
*/
private int fCurrentStateId = IState.UNKNOWN;
/**
* The current state info.
*/
private Object fCurrentStateInfo = null;
/**
* The debug configuration of this session.
*/
private CDebugConfiguration fConfig;
/**
* Constructor for CThread.
* @param target
@ -39,6 +93,22 @@ public class CThread extends CDebugElement
{
super( target );
setCDIThread( cdiThread );
fConfig = new CDebugConfiguration( getCDISession() );
initialize();
getCDISession().getEventManager().addEventListener( this );
}
/**
* Thread initialization:<ul>
* <li>Sets terminated state to <code>false</code></li>
* <li>Determines suspended state from underlying thread</li>
* <li>Sets this threads stack frames to an empty collection</li>
* </ul>
*/
protected void initialize()
{
fStackFrames = Collections.EMPTY_LIST;
setRunning( !getCDIThread().isSuspended() );
}
/* (non-Javadoc)
@ -46,7 +116,8 @@ public class CThread extends CDebugElement
*/
public IStackFrame[] getStackFrames() throws DebugException
{
return null;
List list = computeStackFrames();
return (IStackFrame[])list.toArray( new IStackFrame[list.size()] );
}
/* (non-Javadoc)
@ -54,9 +125,217 @@ public class CThread extends CDebugElement
*/
public boolean hasStackFrames() throws DebugException
{
try
{
return computeStackFrames().size() > 0;
}
catch( DebugException e )
{
// do not throw an exception if the thread resumed while determining
// whether stack frames are present
}
return false;
}
/**
* @see computeStackFrames()
*
* @param refreshChildren whether or not this method should request new stack
* frames from the target
*/
protected synchronized List computeStackFrames( boolean refreshChildren ) throws DebugException
{
if ( isSuspended() )
{
if ( isTerminated() )
{
fStackFrames = Collections.EMPTY_LIST;
}
else if ( refreshChildren )
{
if ( fStackFrames.isEmpty() )
{
fStackFrames = createAllStackFrames();
if ( fStackFrames.isEmpty() )
{
//leave fRefreshChildren == true
//bug 6393
// ?????
return fStackFrames;
}
}
ICStackFrame[] frames = getCDIStackFrames();
// compute new or removed stack frames
int offset = 0, length = frames.length;
if ( length > fStackFrames.size() )
{
// compute new frames
offset = length - fStackFrames.size();
for ( int i = offset - 1; i >= 0; i-- )
{
CStackFrame newStackFrame = new CStackFrame( this, frames[i] );
fStackFrames.add( 0, newStackFrame );
}
length = fStackFrames.size() - offset;
}
else if ( length < fStackFrames.size() )
{
// compute removed children
int removed = fStackFrames.size() - length;
for ( int i = 0; i < removed; i++ )
{
fStackFrames.remove( 0 );
}
}
else
{
if ( frames.length == 0 )
{
fStackFrames = Collections.EMPTY_LIST;
}
else
{
// same number of frames - if top frames are in different
// method, replace all frames
ICStackFrame newTop = frames[0];
ICStackFrame oldTop = ((CStackFrame)fStackFrames.get( 0 ) ).getLastCDIStackFrame();
if (!CStackFrame.equalFrame( newTop, oldTop ) )
{
fStackFrames = createAllStackFrames();
offset = fStackFrames.size();
}
}
}
// update preserved frames
if ( offset < fStackFrames.size() )
{
updateStackFrames( frames, offset, fStackFrames, length );
}
}
fRefreshChildren = false;
}
else
{
return Collections.EMPTY_LIST;
}
return fStackFrames;
}
/**
* Retrieves and returns all underlying stack frames
*
* @return list of <code>StackFrame</code>
* @exception DebugException if this method fails. Reasons include:
* <ul>
* </ul>
*/
protected ICStackFrame[] getCDIStackFrames() throws DebugException
{
try
{
return getCDIThread().getStackFrames();
}
catch( CDIException e )
{
requestFailed( MessageFormat.format( "{0} occurred retrieving stack frames.", new String[] { e.toString() } ), e );
// execution will not reach this line, as
// #targetRequestFailed will thrown an exception
return null;
}
}
/**
* Replaces the underlying stack frame objects in the preserved frames
* list with the current underlying stack frames.
*
* @param newFrames list of current underlying <code>ICStackFrame</code>s.
* Frames from this list are assigned to the underlying frames in
* the <code>oldFrames</code> list.
* @param offset the offset in the lists at which to start replacing
* the old underlying frames
* @param oldFrames list of preserved frames, of type <code>CStackFrame</code>
* @param length the number of frames to replace
*/
protected void updateStackFrames( ICStackFrame[] newFrames,
int offset,
List oldFrames,
int length ) throws DebugException
{
for ( int i = 0; i < length; i++ )
{
CStackFrame frame = (CStackFrame)oldFrames.get( offset );
frame.setCDIStackFrame( newFrames[offset] );
offset++;
}
}
/**
* Returns this thread's current stack frames as a list, computing
* them if required. Returns an empty collection if this thread is
* not currently suspended, or this thread is terminated. This
* method should be used internally to get the current stack frames,
* instead of calling <code>#getStackFrames()</code>, which makes a
* copy of the current list.
* <p>
* Before a thread is resumed a call must be made to one of:<ul>
* <li><code>preserveStackFrames()</code></li>
* <li><code>disposeStackFrames()</code></li>
* </ul>
* If stack frames are disposed before a thread is resumed, stack frames
* are completely re-computed on the next call to this method. If stack
* frames are to be preserved, this method will attempt to re-use any stack
* frame objects which represent the same stack frame as on the previous
* suspend. Stack frames are cached until a subsequent call to preserve
* or dispose stack frames.
* </p>
*
* @return list of <code>IStackFrame</code>
* @exception DebugException if this method fails. Reasons include:
* <ul>
* </ul>
*/
public List computeStackFrames() throws DebugException
{
return computeStackFrames( fRefreshChildren );
}
/**
* @see CThread#computeStackFrames()
*
* This method differs from computeStackFrames() in that it
* always requests new stack frames from the target. As this is
* an expensive operation, this method should only be used
* by clients who know for certain that the stack frames
* on the target have changed.
*/
public List computeNewStackFrames() throws DebugException
{
return computeStackFrames( true );
}
/**
* Helper method for <code>#computeStackFrames()</code> to create all
* underlying stack frames.
*
* @exception DebugException if this method fails. Reasons include:
* <ul>
* <li>Failure communicating with the VM. The DebugException's
* status code contains the underlying exception responsible for
* the failure.</li>
* </ul>
*/
protected List createAllStackFrames() throws DebugException
{
ICStackFrame[] frames = getCDIStackFrames();
List list= new ArrayList( frames.length );
for ( int i = 0; i < frames.length; ++i )
{
CStackFrame newStackFrame = new CStackFrame( this, frames[i] );
list.add( newStackFrame );
}
return list;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IThread#getPriority()
*/
@ -70,7 +349,8 @@ public class CThread extends CDebugElement
*/
public IStackFrame getTopStackFrame() throws DebugException
{
return null;
List c = computeStackFrames();
return ( c.isEmpty() ) ? null : (IStackFrame)c.get( 0 );
}
/* (non-Javadoc)
@ -78,7 +358,7 @@ public class CThread extends CDebugElement
*/
public String getName() throws DebugException
{
return null;
return "Thread " + getCDIThread().getId();
}
/* (non-Javadoc)
@ -94,6 +374,52 @@ public class CThread extends CDebugElement
*/
public void handleDebugEvent( ICEvent event )
{
ICObject source = event.getSource();
if ( source.getCDITarget().equals( getCDITarget() ) )
{
if ( event instanceof ICSuspendedEvent )
{
if ( source instanceof ICThread )
{
handleSuspendedEvent( (ICSuspendedEvent)event );
}
}
else if ( event instanceof ICResumedEvent )
{
if ( source instanceof ICThread )
{
handleResumedEvent( (ICResumedEvent)event );
}
}
else if ( event instanceof ICTerminatedEvent )
{
if ( source instanceof ICThread )
{
handleTerminatedEvent( (ICTerminatedEvent)event );
}
}
else if ( event instanceof ICDisconnectedEvent )
{
if ( source instanceof ICThread )
{
handleDisconnectedEvent( (ICDisconnectedEvent)event );
}
}
else if ( event instanceof ICChangedEvent )
{
if ( source instanceof ICThread )
{
handleChangedEvent( (ICChangedEvent)event );
}
}
else if ( event instanceof ICSteppingEvent )
{
if ( source instanceof ICThread )
{
handleSteppingEvent( (ICSteppingEvent)event );
}
}
}
}
/* (non-Javadoc)
@ -101,7 +427,7 @@ public class CThread extends CDebugElement
*/
public boolean canResume()
{
return false;
return isSuspended() && !getDebugTarget().isSuspended();
}
/* (non-Javadoc)
@ -109,7 +435,7 @@ public class CThread extends CDebugElement
*/
public boolean canSuspend()
{
return false;
return !isSuspended();
}
/* (non-Javadoc)
@ -117,7 +443,7 @@ public class CThread extends CDebugElement
*/
public boolean isSuspended()
{
return false;
return !fRunning && !isTerminated();
}
/* (non-Javadoc)
@ -125,6 +451,23 @@ public class CThread extends CDebugElement
*/
public void resume() throws DebugException
{
if ( !isSuspended() )
{
return;
}
try
{
setRunning( true );
disposeStackFrames();
fireResumeEvent( DebugEvent.CLIENT_REQUEST );
getCDIThread().resume();
}
catch( CDIException e )
{
setRunning( false );
fireSuspendEvent( DebugEvent.CLIENT_REQUEST );
targetRequestFailed( MessageFormat.format( "{0} occurred resuming thread.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
@ -132,6 +475,22 @@ public class CThread extends CDebugElement
*/
public void suspend() throws DebugException
{
if ( isSuspended() )
{
return;
}
try
{
setRunning( false );
getCDIThread().suspend();
fireSuspendEvent( DebugEvent.CLIENT_REQUEST );
}
catch( CDIException e )
{
setRunning( true );
fireResumeEvent( DebugEvent.CLIENT_REQUEST );
targetRequestFailed( MessageFormat.format( "{0} occurred suspending thread.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
@ -139,7 +498,7 @@ public class CThread extends CDebugElement
*/
public boolean canStepInto()
{
return false;
return canStep();
}
/* (non-Javadoc)
@ -147,7 +506,7 @@ public class CThread extends CDebugElement
*/
public boolean canStepOver()
{
return false;
return canStep();
}
/* (non-Javadoc)
@ -155,7 +514,26 @@ public class CThread extends CDebugElement
*/
public boolean canStepReturn()
{
return false;
return canStep();
}
/**
* Returns whether this thread is in a valid state to
* step.
*
* @return whether this thread is in a valid state to
* step
*/
protected boolean canStep()
{
try
{
return fConfig.supportsStepping() && isSuspended() && getTopStackFrame() != null;
}
catch( DebugException e )
{
return false;
}
}
/* (non-Javadoc)
@ -163,7 +541,7 @@ public class CThread extends CDebugElement
*/
public boolean isStepping()
{
return false;
return getCurrentStateId() == IState.STEPPING; // ????
}
/* (non-Javadoc)
@ -171,6 +549,23 @@ public class CThread extends CDebugElement
*/
public void stepInto() throws DebugException
{
if ( !canStepInto() )
{
return;
}
try
{
setRunning( true );
preserveStackFrames();
fireResumeEvent( DebugEvent.STEP_INTO );
getCDIThread().stepInto();
}
catch( CDIException e )
{
setRunning( false );
fireSuspendEvent( DebugEvent.STEP_INTO );
targetRequestFailed( MessageFormat.format( "{0} occurred stepping in thread.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
@ -178,6 +573,23 @@ public class CThread extends CDebugElement
*/
public void stepOver() throws DebugException
{
if ( !canStepOver() )
{
return;
}
try
{
setRunning( true );
preserveStackFrames();
fireResumeEvent( DebugEvent.STEP_OVER );
getCDIThread().stepInto();
}
catch( CDIException e )
{
setRunning( false );
fireSuspendEvent( DebugEvent.STEP_OVER );
targetRequestFailed( MessageFormat.format( "{0} occurred stepping in thread.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
@ -185,6 +597,23 @@ public class CThread extends CDebugElement
*/
public void stepReturn() throws DebugException
{
if ( !canStepReturn() )
{
return;
}
try
{
setRunning( true );
preserveStackFrames();
fireResumeEvent( DebugEvent.STEP_RETURN );
getCDIThread().stepInto();
}
catch( CDIException e )
{
setRunning( false );
fireSuspendEvent( DebugEvent.STEP_RETURN );
targetRequestFailed( MessageFormat.format( "{0} occurred stepping in thread.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
@ -192,7 +621,7 @@ public class CThread extends CDebugElement
*/
public boolean canTerminate()
{
return false;
return !isTerminated();
}
/* (non-Javadoc)
@ -200,7 +629,7 @@ public class CThread extends CDebugElement
*/
public boolean isTerminated()
{
return false;
return getDebugTarget().isTerminated();
}
/* (non-Javadoc)
@ -208,6 +637,7 @@ public class CThread extends CDebugElement
*/
public void terminate() throws DebugException
{
getDebugTarget().terminate();
}
/**
@ -239,15 +669,26 @@ public class CThread extends CDebugElement
*/
protected void setRunning( boolean running )
{
fRunning = running;
}
/**
* Sets whether this thread is terminated
* Preserves stack frames to be used on the next suspend event.
* Iterates through all current stack frames, setting their
* state as invalid. This method should be called before this thread
* is resumed, when stack frames are to be re-used when it later
* suspends.
*
* @param terminated whether this thread is terminated
* @see computeStackFrames()
*/
protected void setTerminated( boolean terminated )
protected void preserveStackFrames()
{
fRefreshChildren = true;
Iterator frames = fStackFrames.iterator();
while( frames.hasNext() )
{
((CStackFrame)frames.next()).setCDIStackFrame( null );
}
}
/**
@ -259,6 +700,13 @@ public class CThread extends CDebugElement
*/
protected synchronized void disposeStackFrames()
{
Iterator it = fStackFrames.iterator();
while( it.hasNext() )
{
((CStackFrame)it.next()).dispose();
}
fStackFrames = Collections.EMPTY_LIST;
fRefreshChildren = true;
}
/**
@ -267,17 +715,185 @@ public class CThread extends CDebugElement
*/
protected void terminated()
{
setTerminated( true );
setRunning( false );
setRunning( false );
cleanup();
fireTerminateEvent();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IState#getCurrentState()
* @see org.eclipse.cdt.debug.core.IState#getCurrentStateId()
*/
public int getCurrentState()
public int getCurrentStateId()
{
return IState.UNKNOWN;
return fCurrentStateId;
}
/**
* Sets the current state identifier.
*
* @param id the identifier
*/
private void setCurrentStateId( int id )
{
fCurrentStateId = id;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IState#getCurrentStateInfo()
*/
public Object getCurrentStateInfo()
{
return fCurrentStateInfo;
}
/**
* Sets the info object of the current state.
*
* @param id the info object
*/
private void setCurrentStateInfo( Object info )
{
fCurrentStateInfo = info;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#canStepIntoInstruction()
*/
public boolean canStepIntoInstruction()
{
return canStepInto();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#canStepOverInstruction()
*/
public boolean canStepOverInstruction()
{
return canStepOver();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#stepIntoInstruction()
*/
public void stepIntoInstruction() throws DebugException
{
if ( !canStepIntoInstruction() )
{
return;
}
try
{
setRunning( true );
preserveStackFrames();
fireResumeEvent( DebugEvent.STEP_INTO );
getCDIThread().stepIntoInstruction();
}
catch( CDIException e )
{
setRunning( false );
fireSuspendEvent( DebugEvent.STEP_INTO );
targetRequestFailed( MessageFormat.format( "{0} occurred stepping in thread.", new String[] { e.toString()} ), e );
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.IInstructionStep#stepOverInstruction()
*/
public void stepOverInstruction() throws DebugException
{
if ( !canStepOverInstruction() )
{
return;
}
try
{
setRunning( true );
preserveStackFrames();
fireResumeEvent( DebugEvent.STEP_OVER );
getCDIThread().stepOverInstruction();
}
catch( CDIException e )
{
setRunning( false );
fireSuspendEvent( DebugEvent.STEP_OVER );
targetRequestFailed( MessageFormat.format( "{0} occurred stepping in thread.", new String[] { e.toString()} ), e );
}
}
private void handleSuspendedEvent( ICSuspendedEvent event )
{
setRunning( false );
setCurrentStateId( IState.SUSPENDED );
ICSessionObject reason = event.getReason();
setCurrentStateInfo( reason );
if ( reason instanceof ICEndSteppingRange )
{
handleEndSteppingRange( (ICEndSteppingRange)reason );
}
else if ( reason instanceof ICBreakpoint )
{
handleBreakpointHit( (ICBreakpoint)reason );
}
else if ( reason instanceof ICSignal )
{
handleSuspendedBySignal( (ICSignal)reason );
}
}
private void handleResumedEvent( ICResumedEvent event )
{
setRunning( true );
setCurrentStateId( IState.RUNNING );
setCurrentStateInfo( null );
fireResumeEvent( DebugEvent.UNSPECIFIED );
}
private void handleEndSteppingRange( ICEndSteppingRange endSteppingRange )
{
fireSuspendEvent( DebugEvent.UNSPECIFIED );
}
private void handleBreakpointHit( ICBreakpoint breakpoint )
{
fireSuspendEvent( DebugEvent.BREAKPOINT );
}
private void handleSuspendedBySignal( ICSignal signal )
{
fireSuspendEvent( DebugEvent.UNSPECIFIED );
}
private void handleTerminatedEvent( ICTerminatedEvent event )
{
setCurrentStateId( IState.TERMINATED );
setCurrentStateInfo( null );
terminated();
}
private void handleDisconnectedEvent( ICDisconnectedEvent event )
{
setCurrentStateId( IState.TERMINATED );
setCurrentStateInfo( null );
terminated();
}
private void handleChangedEvent( ICChangedEvent event )
{
}
private void handleSteppingEvent( ICSteppingEvent event )
{
setCurrentStateId( IState.STEPPING );
setCurrentStateInfo( null );
}
/**
* Cleans up the internal state of this thread.
*
*/
protected void cleanup()
{
getCDISession().getEventManager().removeEventListener( this );
disposeStackFrames();
}
}