/*******************************************************************************
* Copyright (c) 2000, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.debug.core.cdi.CDIException;
import org.eclipse.cdt.debug.core.cdi.model.ICDIRegisterDescriptor;
import org.eclipse.cdt.debug.core.cdi.model.ICDIRegisterGroup;
import org.eclipse.cdt.debug.core.model.ICStackFrame;
import org.eclipse.cdt.debug.core.model.IPersistableRegisterGroup;
import org.eclipse.cdt.debug.core.model.IRegisterDescriptor;
import org.eclipse.cdt.debug.internal.core.model.CDebugTarget;
import org.eclipse.cdt.debug.internal.core.model.CRegisterDescriptor;
import org.eclipse.cdt.debug.internal.core.model.CRegisterGroup;
import org.eclipse.cdt.debug.internal.core.model.CStackFrame;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.model.IRegisterGroup;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Manages all register groups in a debug target.
*/
public class CRegisterManager {
private static final String ELEMENT_REGISTER_GROUP_LIST = "registerGroups"; //$NON-NLS-1$
private static final String ELEMENT_REGISTER_GROUP = "group"; //$NON-NLS-1$
private static final String ATTR_REGISTER_GROUP_MEMENTO = "memento"; //$NON-NLS-1$
/**
* The debug target associated with this manager.
*/
private CDebugTarget fDebugTarget;
/**
* Collection of register groups added to this target. Values are of type <code>CRegisterGroup</code>.
*/
protected List fRegisterGroups;
/**
* The list of all register descriptors.
*/
private IRegisterDescriptor[] fRegisterDescriptors;
private boolean fUseDefaultRegisterGroups = true;
private CStackFrame fCurrentFrame;
private ReentrantLock fInitializationLock = new ReentrantLock();
private boolean fInitialized = false;
/**
* Constructor for CRegisterManager.
*/
public CRegisterManager( CDebugTarget target ) {
fDebugTarget = target;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter( Class adapter ) {
if ( CRegisterManager.class.equals( adapter ) )
return this;
return null;
}
public void dispose() {
DebugPlugin.getDefault().asyncExec(
new Runnable() {
public void run() {
synchronized( fRegisterGroups ) {
Iterator it = fRegisterGroups.iterator();
while( it.hasNext() ) {
((CRegisterGroup)it.next()).dispose();
}
fRegisterGroups.clear();
}
}
} );
}
public IRegisterDescriptor[] getAllRegisterDescriptors() throws DebugException {
return fRegisterDescriptors;
}
public IRegisterGroup[] getRegisterGroups() {
return (IRegisterGroup[])fRegisterGroups.toArray( new IRegisterGroup[fRegisterGroups.size()] );
}
public IRegisterGroup[] getRegisterGroups( CStackFrame frame ) throws DebugException {
setCurrentFrame( frame );
return getRegisterGroups();
}
public void setCurrentFrame( ICStackFrame frame ) throws DebugException {
if ( frame != null && !frame.equals( getCurrentFrame() ) ) {
for ( IRegisterGroup group : getRegisterGroups() ) {
((CRegisterGroup)group).resetRegisterValues();
}
setCurrentFrame0( (CStackFrame)frame );
}
}
public void initialize() {
if ( !fInitialized ) {
synchronized( fInitializationLock ) {
if ( !fInitialized ) {
boolean failed = false;
ICDIRegisterGroup[] groups = new ICDIRegisterGroup[0];
try {
groups = getDebugTarget().getCDITarget().getRegisterGroups();
}
catch( CDIException e ) {
CDebugCorePlugin.log( e );
failed = true;
}
List<CRegisterDescriptor> list = new ArrayList<CRegisterDescriptor>();
for( int i = 0; i < groups.length; ++i ) {
try {
ICDIRegisterDescriptor[] cdiDescriptors = groups[i].getRegisterDescriptors();
for ( int j = 0; j < cdiDescriptors.length; ++j ) {
list.add( new CRegisterDescriptor( groups[i], cdiDescriptors[j] ) );
}
}
catch( CDIException e ) {
CDebugCorePlugin.log( e );
failed = true;
}
}
fRegisterDescriptors = list.toArray( new IRegisterDescriptor[list.size()] );
fInitialized = !failed;
if ( failed )
fRegisterGroups = Collections.emptyList();
else
createRegisterGroups();
}
}
}
}
public void addRegisterGroup( final String name, final IRegisterDescriptor[] descriptors ) {
DebugPlugin.getDefault().asyncExec(
new Runnable() {
public void run() {
fRegisterGroups.add( new CRegisterGroup( getDebugTarget(), name, descriptors ) );
setUseDefaultRegisterGroups( false );
getDebugTarget().fireChangeEvent( DebugEvent.CONTENT );
}
} );
}
public void removeAllRegisterGroups() {
DebugPlugin.getDefault().asyncExec(
new Runnable() {
public void run() {
synchronized( fRegisterGroups ) {
Iterator it = fRegisterGroups.iterator();
while( it.hasNext() ) {
((CRegisterGroup)it.next()).dispose();
}
fRegisterGroups.clear();
}
setUseDefaultRegisterGroups( false );
getDebugTarget().fireChangeEvent( DebugEvent.CONTENT );
}
} );
}
public void removeRegisterGroups( final IRegisterGroup[] groups ) {
DebugPlugin.getDefault().asyncExec(
new Runnable() {
public void run() {
for ( int i = 0; i < groups.length; ++i ) {
((CRegisterGroup)groups[i]).dispose();
}
fRegisterGroups.removeAll( Arrays.asList( groups ) );
setUseDefaultRegisterGroups( false );
getDebugTarget().fireChangeEvent( DebugEvent.CONTENT );
}
} );
}
public void restoreDefaults() {
DebugPlugin.getDefault().asyncExec(
new Runnable() {
public void run() {
synchronized( fRegisterGroups ) {
Iterator it = fRegisterGroups.iterator();
while( it.hasNext() ) {
((CRegisterGroup)it.next()).dispose();
}
fRegisterGroups.clear();
initializeDefaults();
}
getDebugTarget().fireChangeEvent( DebugEvent.CONTENT );
}
} );
}
private void createRegisterGroups() {
fRegisterGroups = Collections.synchronizedList( new ArrayList( 20 ) );
ILaunchConfiguration config = getDebugTarget().getLaunch().getLaunchConfiguration();
try {
String memento = config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS, "" ); //$NON-NLS-1$
if ( memento != null && memento.length() > 0 ) {
initializeFromMemento( memento );
return;
}
}
catch( CoreException e ) {
}
initializeDefaults();
}
public void targetSuspended() {
Iterator it = fRegisterGroups.iterator();
while( it.hasNext() ) {
((CRegisterGroup)it.next()).targetSuspended();
}
}
public CDebugTarget getDebugTarget() {
return fDebugTarget;
}
private void initializeFromMemento( String memento ) throws CoreException {
Node node = DebugPlugin.parseDocument( memento );
if ( node.getNodeType() != Node.ELEMENT_NODE ) {
abort( InternalDebugCoreMessages.getString( "CRegisterManager.0" ), null ); //$NON-NLS-1$
}
Element element = (Element)node;
if ( !ELEMENT_REGISTER_GROUP_LIST.equals( element.getNodeName() ) ) {
abort( InternalDebugCoreMessages.getString( "CRegisterManager.1" ), null ); //$NON-NLS-1$
}
Node childNode = element.getFirstChild();
while( childNode != null ) {
if ( childNode.getNodeType() == Node.ELEMENT_NODE ) {
Element child = (Element)childNode;
if ( ELEMENT_REGISTER_GROUP.equals( child.getNodeName() ) ) {
String groupMemento = child.getAttribute( ATTR_REGISTER_GROUP_MEMENTO );
CRegisterGroup group = new CRegisterGroup( getDebugTarget() );
try {
group.initializeFromMemento( groupMemento );
doAddRegisterGroup( group );
}
catch( CoreException e ) {
// skip this group
}
}
}
childNode = childNode.getNextSibling();
}
setUseDefaultRegisterGroups( false );
}
protected void initializeDefaults() {
setUseDefaultRegisterGroups( true );
String current = null;
int startIndex = 0;
for ( int i = 0; i < fRegisterDescriptors.length; ++i ) {
CRegisterDescriptor d = (CRegisterDescriptor)fRegisterDescriptors[i];
if ( current != null && d.getGroupName().compareTo( current ) != 0 ) {
IRegisterDescriptor[] descriptors = new IRegisterDescriptor[i - startIndex];
System.arraycopy( fRegisterDescriptors, startIndex, descriptors, 0, descriptors.length );
fRegisterGroups.add( new CRegisterGroup( getDebugTarget(), current, descriptors ) );
startIndex = i;
}
current = d.getGroupName();
}
if ( startIndex < fRegisterDescriptors.length ) {
IRegisterDescriptor[] descriptors = new IRegisterDescriptor[fRegisterDescriptors.length - startIndex];
System.arraycopy( fRegisterDescriptors, startIndex, descriptors, 0, descriptors.length );
fRegisterGroups.add( new CRegisterGroup( getDebugTarget(), current, descriptors ) );
}
}
protected synchronized void doAddRegisterGroup( IRegisterGroup group ) {
fRegisterGroups.add( group );
}
public void save() {
ILaunchConfiguration config = getDebugTarget().getLaunch().getLaunchConfiguration();
try {
ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
wc.setAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS, getMemento() );
wc.doSave();
}
catch( CoreException e ) {
CDebugCorePlugin.log( e );
}
}
private String getMemento() throws CoreException {
if ( useDefaultRegisterGroups() || fRegisterGroups == null )
return ""; //$NON-NLS-1$
Document document = DebugPlugin.newDocument();
Element element = document.createElement( ELEMENT_REGISTER_GROUP_LIST );
Iterator it = fRegisterGroups.iterator();
while( it.hasNext() ) {
CRegisterGroup group = (CRegisterGroup)it.next();
Element child = document.createElement( ELEMENT_REGISTER_GROUP );
child.setAttribute( ATTR_REGISTER_GROUP_MEMENTO, group.getMemento() );
element.appendChild( child );
}
document.appendChild( element );
return DebugPlugin.serializeDocument( document );
}
private void abort( String message, Throwable exception ) throws CoreException {
IStatus status = new Status( IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), CDebugCorePlugin.INTERNAL_ERROR, message, exception );
throw new CoreException( status );
}
public IRegisterDescriptor findDescriptor( String groupName, String name ) {
for ( int i = 0; i < fRegisterDescriptors.length; ++i ) {
IRegisterDescriptor d = fRegisterDescriptors[i];
if ( groupName.equals( d.getGroupName() ) && name.equals( d.getName() ) )
return d;
}
return null;
}
public void modifyRegisterGroup( final IPersistableRegisterGroup group, final IRegisterDescriptor[] descriptors ) {
DebugPlugin.getDefault().asyncExec(
new Runnable() {
public void run() {
group.setRegisterDescriptors( descriptors );
((CRegisterGroup)group).fireChangeEvent( DebugEvent.CONTENT );
}
} );
}
protected boolean useDefaultRegisterGroups() {
return fUseDefaultRegisterGroups;
}
protected void setUseDefaultRegisterGroups( boolean useDefaultRegisterGroups ) {
fUseDefaultRegisterGroups = useDefaultRegisterGroups;
}
public CStackFrame getCurrentFrame() {
return fCurrentFrame;
}
private void setCurrentFrame0( CStackFrame currentFrame ) {
fCurrentFrame = currentFrame;
}
}