diff --git a/debug/org.eclipse.cdt.debug.core/cdi/org/eclipse/cdt/debug/core/cdi/model/ICDIMemoryBlockManagement2.java b/debug/org.eclipse.cdt.debug.core/cdi/org/eclipse/cdt/debug/core/cdi/model/ICDIMemoryBlockManagement2.java new file mode 100644 index 00000000000..9689fbb65e6 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/cdi/org/eclipse/cdt/debug/core/cdi/model/ICDIMemoryBlockManagement2.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * 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: + * Freescale Semiconductor - Initial API + *******************************************************************************/ + +package org.eclipse.cdt.debug.core.cdi.model; + +import java.math.BigInteger; + +import org.eclipse.cdt.debug.core.cdi.CDIException; + +/** + * Extension of ICDIMemoryBlockManagement + * + * @since May 26, 2006 + */ +public interface ICDIMemoryBlockManagement2 extends ICDIMemoryBlockManagement { + + /** + * Returns a memory block specified by given parameters. Differs + * from {@link ICDIMemoryBlockManagement#createMemoryBlock(String, int, int)} + * in that this support memory spaces. + * @param address + * @param memorySpaceID - value is meaningful only to the backend + * @param units - number of units + * @param wordSize - The size of each memory word in bytes + * @return a memory block with the specified identifier + * @throws CDIException on failure. Reasons include: + */ + ICDIMemoryBlock createMemoryBlock(BigInteger address, String memorySpaceID, int units, int wordSize) + throws CDIException; +} diff --git a/debug/org.eclipse.cdt.debug.core/cdi/org/eclipse/cdt/debug/core/cdi/model/ICDIMemorySpaceManagement.java b/debug/org.eclipse.cdt.debug.core/cdi/org/eclipse/cdt/debug/core/cdi/model/ICDIMemorySpaceManagement.java new file mode 100644 index 00000000000..f3c315750cd --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/cdi/org/eclipse/cdt/debug/core/cdi/model/ICDIMemorySpaceManagement.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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: + * Freescale Semiconductor - Initial API + *******************************************************************************/ + +package org.eclipse.cdt.debug.core.cdi.model; + +import java.math.BigInteger; + +/** + * The memory space manager provides varous memory-space related operations. + * The backend implementation of ICDITarget should implement this interface + * as well if the target supports memory spaces. + */ +public interface ICDIMemorySpaceManagement extends ICDIObject { + + /** + * Optionally provides the string encoding of a memory space qualified address. + * CDT provides a default encoding of :. + * If this is adequate, the client can return null from this function. + * + * @param address - a numeric address + * @param memorySpaceID - a string which represents the memory space + * @return the encoded string representation of the address or null + */ + String addressToString(BigInteger address, String memorySpaceID); + + /** + * Provides the memory spaces available. + * + * @return an array of memory space identifiers + */ + String [] getMemorySpaces(); + +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CMemoryBlockRetrievalExtension.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CMemoryBlockRetrievalExtension.java index ae660202614..b2be0290d15 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CMemoryBlockRetrievalExtension.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CMemoryBlockRetrievalExtension.java @@ -19,6 +19,8 @@ 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.ICDIExpression; +import org.eclipse.cdt.debug.core.cdi.model.ICDIMemorySpaceManagement; +import org.eclipse.cdt.debug.core.cdi.model.ICDITarget; import org.eclipse.cdt.debug.core.model.ICType; import org.eclipse.cdt.debug.core.model.ICValue; import org.eclipse.cdt.debug.internal.core.model.CDebugTarget; @@ -200,6 +202,39 @@ public class CMemoryBlockRetrievalExtension extends PlatformObject implements IM return new CMemoryBlockExtension( getDebugTarget(), expression, address ); } + /** + * Variant of getExtendedMemoryBlock that takes a memory space ID. Note that unlike that one, + * this method is not part of IMemoryBlockRetrievalExtension; it is not exercised by the + * platform. We invoke it internally in CDT from our hook into the platform's "add memory + * monitor" action. + * + * @param address - a numric address value, hex or decimal. An expression + * (even something simple like 10000 +1) is not allowed. + * @param memorySpaceID - identifies the memory space; cannot be null. + * @param selected - the object selected in the Debug view + * @return + * @throws DebugException + */ + public IMemoryBlockExtension getMemoryBlockWithMemorySpaceID( String address, String memorySpaceID, Object selected ) throws DebugException { + String msg = null; + try { + if (selected instanceof IDebugElement) { + IDebugElement debugElement = (IDebugElement)selected; + IDebugTarget target = debugElement.getDebugTarget(); + if ( target instanceof CDebugTarget ) { + if ( address != null ) { + BigInteger addr = ( address.startsWith( "0x" ) ) ? new BigInteger( address.substring( 2 ), 16 ) : new BigInteger( address ); //$NON-NLS-1$ + return new CMemoryBlockExtension( (CDebugTarget)target, addr, memorySpaceID ); + } + } + } + } + catch( NumberFormatException e ) { + msg = MessageFormat.format( InternalDebugCoreMessages.getString( "CMemoryBlockRetrievalExtension.4" ), new String[] { address } ); //$NON-NLS-1$ + } + throw new DebugException( new Status( IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), DebugException.REQUEST_FAILED, msg, null ) ); + } + private CStackFrame getStackFrame( IDebugElement selected ) throws DebugException { if ( selected instanceof CStackFrame ) { return (CStackFrame)selected; @@ -234,4 +269,26 @@ public class CMemoryBlockRetrievalExtension extends PlatformObject implements IM public void dispose() { } + + /** + * Checks the CDI backend to see is memory spaces are supported + * + * @return true if the backend supports memory spaces + */ + public boolean supportsMemorySpaces() { + return fDebugTarget.getCDITarget() instanceof ICDIMemorySpaceManagement; + } + + /** + * Get the list of available memory spaces from the CDI backend + * + * @return an array of memory space identifiers + */ + public String [] getMemorySpaces() { + ICDITarget cdiTarget = fDebugTarget.getCDITarget(); + if (cdiTarget instanceof ICDIMemorySpaceManagement) + return ((ICDIMemorySpaceManagement)cdiTarget).getMemorySpaces(); + + return new String[0]; + } } diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties index 531ebc31941..c2e781c165f 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/InternalDebugCoreMessages.properties @@ -13,6 +13,7 @@ CMemoryBlockRetrievalExtension.0=Expression ''{0}'' evaluated to invalid address CMemoryBlockRetrievalExtension.1=Invalid expression type: ''{0}'' CMemoryBlockRetrievalExtension.2=Invalid expression: ''{0}'' CMemoryBlockRetrievalExtension.3=Memory initialization: invalid memento. +CMemoryBlockRetrievalExtension.4=Invalid address: ''{0}'' DebugConfiguration.0=This debugger no longer supports this operation CDebugAdapter.0=This debugger does not support debugging external files CDebugAdapter.1=Debugger Process diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CMemoryBlockExtension.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CMemoryBlockExtension.java index c3bd04f7aa1..f09cafebd2e 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CMemoryBlockExtension.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CMemoryBlockExtension.java @@ -21,7 +21,10 @@ import org.eclipse.cdt.debug.core.cdi.event.ICDIMemoryChangedEvent; import org.eclipse.cdt.debug.core.cdi.event.ICDIRestartedEvent; import org.eclipse.cdt.debug.core.cdi.event.ICDIResumedEvent; import org.eclipse.cdt.debug.core.cdi.model.ICDIMemoryBlock; +import org.eclipse.cdt.debug.core.cdi.model.ICDIMemoryBlockManagement2; +import org.eclipse.cdt.debug.core.cdi.model.ICDIMemorySpaceManagement; import org.eclipse.cdt.debug.core.cdi.model.ICDIObject; +import org.eclipse.cdt.debug.core.cdi.model.ICDITarget; import org.eclipse.cdt.debug.core.model.IExecFileInfo; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; @@ -45,6 +48,12 @@ public class CMemoryBlockExtension extends CDebugElement implements IMemoryBlock */ private BigInteger fBaseAddress; + /** + * The memory space identifier; will be null for backends that + * don't require memory space support + */ + private String fMemorySpaceID; + /** * The underlying CDI memory block. */ @@ -77,6 +86,24 @@ public class CMemoryBlockExtension extends CDebugElement implements IMemoryBlock fWordSize = wordSize; } + /** + * Constructor for CMemoryBlockExtension that supports memory spaces + * + */ + public CMemoryBlockExtension( CDebugTarget target, BigInteger baseAddress, String memorySpaceID ) { + super( target ); + fBaseAddress = baseAddress; + fMemorySpaceID = memorySpaceID; + fWordSize = 1; + if (target.getCDITarget() instanceof ICDIMemorySpaceManagement) + fExpression = ((ICDIMemorySpaceManagement)target.getCDITarget()).addressToString(baseAddress, memorySpaceID); + + if (fExpression == null) + // If the backend supports memory spaces, it should implement ICDIMemorySpaceManagement + // If not, we use a default encoding + fExpression = memorySpaceID + ':' + baseAddress.toString(16); + } + /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getExpression() */ @@ -264,7 +291,14 @@ public class CMemoryBlockExtension extends CDebugElement implements IMemoryBlock } private ICDIMemoryBlock createCDIBlock( BigInteger address, long length, int wordSize ) throws CDIException { - ICDIMemoryBlock block = ((CDebugTarget)getDebugTarget()).getCDITarget().createMemoryBlock( address.toString(), (int)length, wordSize ); + ICDIMemoryBlock block = null; + CDebugTarget target = (CDebugTarget)getDebugTarget(); + ICDITarget cdiTarget = target.getCDITarget(); + if ((fMemorySpaceID != null) && (cdiTarget instanceof ICDIMemoryBlockManagement2)) { + block = ((ICDIMemoryBlockManagement2)cdiTarget).createMemoryBlock(address, fMemorySpaceID, (int)length, wordSize); + } else { + block = cdiTarget.createMemoryBlock( address.toString(), (int)length, wordSize ); + } block.setFrozen( false ); getCDISession().getEventManager().addEventListener( this ); return block; @@ -456,4 +490,18 @@ public class CMemoryBlockExtension extends CDebugElement implements IMemoryBlock } return new MemoryByte( value, flags ); } + + + /** + * Provides the memory space associated with this block if and only if the + * block was created with an address value + memory space qualifier. If the + * block was created from an expression, this method should return null-- + * even if the target CDI backend supports memory spaces. + * + * @return a memory space ID or null + * expression + */ + public String getMemorySpaceID() { + return fMemorySpaceID; + } } diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/elements/adapters/CMemoryAdapterFactory.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/elements/adapters/CMemoryAdapterFactory.java new file mode 100644 index 00000000000..9289c8af1ef --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/elements/adapters/CMemoryAdapterFactory.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * 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: + * Freescale Semiconductor - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.cdt.debug.internal.ui.elements.adapters; + +import org.eclipse.cdt.debug.internal.core.CMemoryBlockRetrievalExtension; +import org.eclipse.cdt.debug.internal.core.model.CMemoryBlockExtension; +import org.eclipse.cdt.debug.internal.ui.views.memory.AddMemoryBlocks; +import org.eclipse.cdt.debug.internal.ui.views.memory.MemoryBlockLabelDecorator; +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.debug.ui.actions.IAddMemoryBlocksTarget; +import org.eclipse.jface.viewers.ILabelDecorator; + +/** + * Provides the IAdaptable mapping for things related to the memory-space + * extension of the platform's Memory view + */ +public class CMemoryAdapterFactory implements IAdapterFactory { + + private static IAddMemoryBlocksTarget fgAddMemoryBlocks = new AddMemoryBlocks(); + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, + * java.lang.Class) + */ + public Object getAdapter(Object adaptableObject, Class adapterType) { + if (adapterType.isInstance(adaptableObject)) { + return adaptableObject; + } + + if (adapterType.equals(IAddMemoryBlocksTarget.class)) { + if (adaptableObject instanceof CMemoryBlockRetrievalExtension) { + if (((CMemoryBlockRetrievalExtension)adaptableObject).supportsMemorySpaces()) + return fgAddMemoryBlocks; + } + } + + if (adapterType.equals(ILabelDecorator.class)) { + if (adaptableObject instanceof CMemoryBlockExtension) { + // If a memory space isn't involved, the standard label is fine + CMemoryBlockExtension memBlock = (CMemoryBlockExtension)adaptableObject; + if (memBlock.getMemorySpaceID() != null) + return new MemoryBlockLabelDecorator(memBlock); + } + } + + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList() + */ + public Class[] getAdapterList() { + return new Class[] { IAddMemoryBlocksTarget.class, ILabelDecorator.class }; + } +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/AddMemoryBlockDialog.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/AddMemoryBlockDialog.java new file mode 100644 index 00000000000..07a5f90f847 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/AddMemoryBlockDialog.java @@ -0,0 +1,298 @@ +/******************************************************************************* + * 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: + * Freescale Semiconductor - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.cdt.debug.internal.ui.views.memory; + +import java.util.ArrayList; + +import org.eclipse.cdt.debug.internal.core.CMemoryBlockRetrievalExtension; +import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.events.VerifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.PlatformUI; + +/** + * Dialog CDT puts up when adding a memory monitor to the memory view for a + * debug target that supports memory spaces. + *

+ * It differs from the platform one in that you can enter an expression or + * an memory space + address pair. + * + * @since 3.2 + */ +public class AddMemoryBlockDialog extends TrayDialog implements ModifyListener, FocusListener, VerifyListener { + + private Combo fAddressInput; + private Combo fMemorySpaceInput; + private Combo fExpressionInput; + private String fExpression; + private String fAddress; + private String fMemorySpace; + private boolean fExpressionEntered; + private CMemoryBlockRetrievalExtension fMemRetrieval; + private Button fEnterAddr; + private Button fEnterExpression; + + private static boolean sfExpressionSetLast = false; // used to persist the default entry-type selection + + private static ArrayList sAddressHistory = new ArrayList(); + private static ArrayList sExpressionHistory = new ArrayList(); + + public AddMemoryBlockDialog(Shell parentShell, + IMemoryBlockRetrieval memRetrieval) { + super(parentShell); + + setShellStyle(getShellStyle() | SWT.RESIZE); + + if (memRetrieval instanceof CMemoryBlockRetrievalExtension) { + fMemRetrieval = (CMemoryBlockRetrievalExtension)memRetrieval; + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + protected Control createDialogArea(Composite parent) { + PlatformUI.getWorkbench().getHelpSystem().setHelp( + parent, + IDebugUIConstants.PLUGIN_ID + + ".MonitorMemoryBlockDialog_context"); //$NON-NLS-1$ + + // The button bar will work better if we make the parent composite + // a single column grid layout. For the widgets we add, we want a + // a two-column grid, so we just create a sub composite for that. + GridLayout gridLayout = new GridLayout(); + parent.setLayout(gridLayout); + GridData gridData = new GridData(GridData.FILL_BOTH); + parent.setLayoutData(gridData); + Composite composite = new Composite(parent, SWT.None); + gridLayout = new GridLayout(); + gridLayout.numColumns = 2; + composite.setLayout(gridLayout); + gridData = new GridData(GridData.FILL_BOTH); + composite.setLayoutData(gridData); + parent = composite; // for all our widgets, the two-column composite is the real parent + + fEnterAddr = new Button(parent, SWT.RADIO); + + // take this opportunity to get the width of just the radion buton + // (w/no text), as we'll need it below + int buttonWidth = fEnterAddr.computeSize(SWT.DEFAULT, SWT.DEFAULT, false).x; + + fEnterAddr.setText(Messages.AddMemBlockDlg_enterMemSpaceAndAddr); + gridData = new GridData(GridData.FILL_HORIZONTAL); + gridData.horizontalSpan = 2; + fEnterAddr.setLayoutData(gridData); + + fMemorySpaceInput = new Combo(parent, SWT.BORDER | SWT.READ_ONLY); + gridData = new GridData(); + gridData.horizontalIndent = buttonWidth; + fMemorySpaceInput.setLayoutData(gridData); + fMemorySpaceInput.addFocusListener(this); + + // Populate the memory space combobox with the available spaces + if (fMemRetrieval != null) { + String [] memorySpaces = fMemRetrieval.getMemorySpaces(); + for (int i = 0; i < memorySpaces.length; i++) + fMemorySpaceInput.add(memorySpaces[i]); + + if (memorySpaces.length > 0) + fMemorySpaceInput.select(0); + } + + fAddressInput = new Combo(parent, SWT.BORDER); + gridData = new GridData(GridData.FILL_HORIZONTAL); + fAddressInput.setLayoutData(gridData); + fAddressInput.addModifyListener(this); + fAddressInput.addFocusListener(this); + fAddressInput.addVerifyListener(this); + + fEnterExpression = new Button(parent, SWT.RADIO); + fEnterExpression.setText(Messages.AddMemBlockDlg_enterExpression); + gridData = new GridData(GridData.FILL_HORIZONTAL); + gridData.horizontalSpan = 2; + fEnterExpression.setLayoutData(gridData); + + fExpressionInput = new Combo(parent, SWT.BORDER); + gridData = new GridData(GridData.FILL_HORIZONTAL); + gridData.horizontalSpan = 2; + gridData.horizontalIndent = buttonWidth; + fExpressionInput.setLayoutData(gridData); + fExpressionInput.addModifyListener(this); + fExpressionInput.addFocusListener(this); + + // add the history into the combo boxes + String[] history = getHistory(sExpressionHistory); + for (int i = 0; i < history.length; i++) + fExpressionInput.add(history[i]); + + history = getHistory(sAddressHistory); + for (int i = 0; i < history.length; i++) + fAddressInput.add(history[i]); + + fExpressionInput.addFocusListener(this); + + fEnterExpression.setSelection(sfExpressionSetLast); + fEnterAddr.setSelection(!sfExpressionSetLast); + if (sfExpressionSetLast) { + fExpressionInput.forceFocus(); + } else { + fAddressInput.forceFocus(); + } + + return parent; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) + */ + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + + // use the same title used by the platform dialog + newShell.setText(Messages.AddMemBlockDlg_MonitorMemory); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#okPressed() + */ + protected void okPressed() { + + fExpressionEntered = fEnterExpression.getSelection(); + fExpression = fExpressionInput.getText(); + fAddress = fAddressInput.getText(); + fMemorySpace = fMemorySpaceInput.getText(); + + // add to HISTORY list; add to the platform dialog's for the expression + if (fExpression.length() > 0) + addHistory(sExpressionHistory, fExpression); + if (fAddress.length() > 0) + addHistory(sAddressHistory, fAddress); + + // this will persist the entry type from one dialog invocation to another + sfExpressionSetLast = fExpressionEntered; + + super.okPressed(); + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent) + */ + public void modifyText(ModifyEvent e) { + // if user enters text into one of the two input options, disable/gray the other + // to make the mutual exlusivity obvious + fAddressInput.setEnabled(fExpressionInput.getText().length() == 0); + fEnterAddr.setEnabled(fExpressionInput.getText().length() == 0); + fMemorySpaceInput.setEnabled(fExpressionInput.getText().length() == 0); + fExpressionInput.setEnabled(fAddressInput.getText().length() == 0); + fEnterExpression.setEnabled(fAddressInput.getText().length() == 0); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.TrayDialog#createButtonBar(org.eclipse.swt.widgets.Composite) + */ + protected Control createButtonBar(Composite parent) { + return super.createButtonBar(parent); + } + + public String getExpression() { + return fExpression; + } + + public String getAddress() { + return fAddress; + } + + public String getMemorySpace() { + return fMemorySpace; + } + + public boolean wasExpressionEntered() { + return fExpressionEntered; + } + + private static void addHistory(ArrayList list, String item) { + if (!list.contains(item)) + list.add(0, item); + + if (list.size() > 5) + list.remove(list.size()-1); + } + + private static String[] getHistory(ArrayList list) { + return (String[])list.toArray(new String[list.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) + */ + public void focusGained(FocusEvent e) { + // when the user gives focus to one of the combo boxes, shift the radio button state accordingly + if (e.widget == fAddressInput || e.widget == fMemorySpaceInput) { + fEnterAddr.setSelection(true); + fEnterExpression.setSelection(false); + } + else if (e.widget == fExpressionInput) { + fEnterAddr.setSelection(false); + fEnterExpression.setSelection(true); + } + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent) + */ + public void focusLost(FocusEvent e) { + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.VerifyListener#verifyText(org.eclipse.swt.events.VerifyEvent) + */ + public void verifyText(VerifyEvent event) { + if (event.widget == fAddressInput) { + // assume we won't allow it + event.doit = false; + + char c = event.character; + + String textAlreadyInControl = ((Combo)event.widget).getText(); + + if ((c == 'x') && (textAlreadyInControl.length() == 1) + && textAlreadyInControl.charAt(0) == '0') { + // allow 'x' if it's the second character and the first is zero. + // Note that this level of verification has a hole; user can use + // ISO control characters (e.g., the Delete key) to move the 'x' + // in the first slot. Oh well; this doesn't need to be bullet proof + event.doit = true; + } else if ((c == '\b') || // allow backspace + Character.isDigit(c) || ('a' <= c && c <= 'f') + || ('A' <= c && c <= 'F')) { + event.doit = true; + } else if (Character.isISOControl(c)) { + event.doit = true; + } + } + } +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/AddMemoryBlocks.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/AddMemoryBlocks.java new file mode 100644 index 00000000000..11583d794e7 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/AddMemoryBlocks.java @@ -0,0 +1,296 @@ +/******************************************************************************* + * 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: + * Freescale Semiconductor - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.cdt.debug.internal.ui.views.memory; + +import java.util.ArrayList; +import java.util.StringTokenizer; + +import org.eclipse.cdt.debug.internal.core.CMemoryBlockRetrievalExtension; +import org.eclipse.cdt.debug.ui.CDebugUIPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockExtension; +import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.actions.IAddMemoryBlocksTarget; +import org.eclipse.debug.ui.memory.IMemoryRendering; +import org.eclipse.debug.ui.memory.IMemoryRenderingContainer; +import org.eclipse.debug.ui.memory.IMemoryRenderingSite; +import org.eclipse.debug.ui.memory.IMemoryRenderingType; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.progress.UIJob; + +/** + * Adds memory blocks to the Memory view. + * + *

+ * CDT adapter logic will link us to a CMemoryBlockRetrievalExtension + * if and only if the CDI backend support memory spaces. When this is the case, + * the platform will call us to add a memory monitor to the Memory view. We + * must put up a dialog, handle the user input, create the memory blocks + * with default renderings and add them to the view. + * + *

+ * @since 3.2 + * + */ +public class AddMemoryBlocks implements IAddMemoryBlocksTarget { + + public void addMemoryBlocks(IWorkbenchPart part, ISelection selection) throws CoreException { + + if (!(part instanceof IMemoryRenderingSite)) + return; + + IAdaptable debugViewElement = DebugUITools.getDebugContext(); + + + CMemoryBlockRetrievalExtension cdtRetrieval = null; + + { + IMemoryBlockRetrieval retrieval = (IMemoryBlockRetrieval)debugViewElement.getAdapter(IMemoryBlockRetrieval.class); + + if (retrieval == null && debugViewElement instanceof IDebugElement) + retrieval = ((IDebugElement)debugViewElement).getDebugTarget(); + + if (retrieval == null || !(retrieval instanceof CMemoryBlockRetrievalExtension)) + return; + + cdtRetrieval = (CMemoryBlockRetrievalExtension) retrieval; + } + + Shell shell = CDebugUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); + + // create dialog to ask for expression/address to block + AddMemoryBlockDialog dialog = new AddMemoryBlockDialog(shell, cdtRetrieval); + dialog.open(); + int returnCode = dialog.getReturnCode(); + if (returnCode == Window.CANCEL) + return; + + String input = (dialog.getAddress().length() > 0) ? dialog.getAddress() + : dialog.getExpression(); + + ArrayList list = new ArrayList(); + + if (input.length() == 0) + list.add(""); //$NON-NLS-1$ + else { + StringTokenizer tokenizer = new StringTokenizer(input, ","); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) + list.add(tokenizer.nextToken()); + } + + final String[] addrsOrExprs = (String[]) list.toArray(new String[list.size()]); + + ParamHolder params; + if (dialog.wasExpressionEntered()) + params = new ExpressionsHolder(addrsOrExprs); + else + params = new AddressAndSpaceHolder(addrsOrExprs, dialog.getMemorySpace()); + + final IAdaptable debugViewElement_f = debugViewElement; + final CMemoryBlockRetrievalExtension retrieval_f = cdtRetrieval; + final ParamHolder params_f = params; + final IMemoryRenderingSite memRendSite = (IMemoryRenderingSite) part; + Job job = new Job("Add Memory Block") { //$NON-NLS-1$ + protected IStatus run(IProgressMonitor monitor) { + addMemoryBlocks(debugViewElement_f, retrieval_f, params_f, + memRendSite); + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + + public boolean canAddMemoryBlocks(IWorkbenchPart part, ISelection selection) + throws CoreException { + return true; + } + + public boolean supportsAddMemoryBlocks(IWorkbenchPart part) { + return (IDebugUIConstants.ID_MEMORY_VIEW.equals(part.getSite().getId())); + } + + // In order to avoid duplicating the addMemoryBlocks method--one + // version for expressions, one for memory-space+address, we pass in a + // an opaque parameter and let the logic within addMemoryBlocks + // differentiate where needed via isinstanceof + + private class ParamHolder { + } + + class AddressAndSpaceHolder extends ParamHolder { + public AddressAndSpaceHolder(final String[] addresses, + final String memorySpace) { + this.addresses = addresses; + this.memorySpace = memorySpace; + } + + public String[] addresses; + + public String memorySpace; + } + + private class ExpressionsHolder extends ParamHolder { + public ExpressionsHolder(final String[] expressions) { + this.expressions = expressions; + } + + public String[] expressions; + } + + private void addMemoryBlocks(IAdaptable debugViewElement, + CMemoryBlockRetrievalExtension memRetrieval, + final ParamHolder params, IMemoryRenderingSite memRendSite) { + + final String[] addrsOrExprs = (params instanceof AddressAndSpaceHolder) ? ((AddressAndSpaceHolder) params).addresses + : ((ExpressionsHolder) params).expressions; + + for (int i = 0; i < addrsOrExprs.length; i++) { + String addrOrExpr = addrsOrExprs[i].trim(); + try { + + // get extended memory block with the expression or address + // entered + IMemoryBlockExtension memBlock; + + if (params instanceof AddressAndSpaceHolder) + memBlock = memRetrieval.getMemoryBlockWithMemorySpaceID( + addrOrExpr, + ((AddressAndSpaceHolder) params).memorySpace, + debugViewElement); + else + memBlock = memRetrieval.getExtendedMemoryBlock(addrOrExpr, + debugViewElement); + + // add block to memory block manager + if (memBlock != null) { + IMemoryBlock[] memArray = new IMemoryBlock[] { memBlock }; + + DebugPlugin.getDefault().getMemoryBlockManager().addMemoryBlocks(memArray); + + addDefaultRenderings(memBlock, memRendSite); + } else { + // open error if it failed to retrieve a memory block + openError(Messages.AddMemBlocks_title, + Messages.AddMemBlocks_noMemoryBlock, + null); + } + } catch (DebugException e1) { + openError(Messages.AddMemBlocks_title, + Messages.AddMemBlocks_failed, e1); + } catch (NumberFormatException e2) { + String message = Messages.AddMemBlocks_failed + "\n" + Messages.AddMemBlocks_input_invalid; //$NON-NLS-1$ + openError(Messages.AddMemBlocks_title, message, + null); + } + } + } + + private void addDefaultRenderings(IMemoryBlock memoryBlock, + IMemoryRenderingSite memRendSite) { + + // This method was mostly lifted from the platform's AddMemoryBlockAction + + IMemoryRenderingType primaryType = DebugUITools.getMemoryRenderingManager().getPrimaryRenderingType( + memoryBlock); + IMemoryRenderingType renderingTypes[] = DebugUITools.getMemoryRenderingManager().getDefaultRenderingTypes( + memoryBlock); + + // create primary rendering + try { + if (primaryType != null) { + createRenderingInContainer(memoryBlock, memRendSite, + primaryType, IDebugUIConstants.ID_RENDERING_VIEW_PANE_1); + } else if (renderingTypes.length > 0) { + primaryType = renderingTypes[0]; + createRenderingInContainer(memoryBlock, memRendSite, + renderingTypes[0], + IDebugUIConstants.ID_RENDERING_VIEW_PANE_1); + } + } catch (CoreException e1) { + CDebugUIPlugin.log(e1); + } + + for (int i = 0; i < renderingTypes.length; i++) { + try { + boolean create = true; + if (primaryType != null) { + if (primaryType.getId().equals(renderingTypes[i].getId())) + create = false; + } + if (create) + createRenderingInContainer(memoryBlock, memRendSite, + renderingTypes[i], + IDebugUIConstants.ID_RENDERING_VIEW_PANE_2); + } catch (CoreException e) { + CDebugUIPlugin.log(e); + } + } + } + + private void createRenderingInContainer(IMemoryBlock memoryBlock, + IMemoryRenderingSite memRendSite, IMemoryRenderingType primaryType, + String paneId) throws CoreException { + + // This method was mostly lifted from the platform's AddMemoryBlockAction + + IMemoryRendering rendering = primaryType.createRendering(); + IMemoryRenderingContainer container = memRendSite.getContainer(paneId); + rendering.init(container, memoryBlock); + container.addMemoryRendering(rendering); + } + + /** + * Helper function to open an error dialog. + * @param title + * @param message + * @param e + */ + static public void openError (final String title, final String message, final Exception e) + { + UIJob uiJob = new UIJob("open error"){ //$NON-NLS-1$ + + public IStatus runInUIThread(IProgressMonitor monitor) { + // open error for the exception + String detail = ""; //$NON-NLS-1$ + if (e != null) + detail = e.getMessage(); + + Shell shell = CDebugUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); + + MessageDialog.openError( + shell, + title, + message + "\n" + detail); //$NON-NLS-1$ + return Status.OK_STATUS; + }}; + uiJob.setSystem(true); + uiJob.schedule(); + } + +} + diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/MemoryBlockLabelDecorator.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/MemoryBlockLabelDecorator.java new file mode 100644 index 00000000000..349f45daa98 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/MemoryBlockLabelDecorator.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * 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: + * Freescale Semiconductor - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.cdt.debug.internal.ui.views.memory; + +import org.eclipse.cdt.debug.internal.core.model.CMemoryBlockExtension; +import org.eclipse.jface.viewers.ILabelDecorator; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.swt.graphics.Image; + +/** + * Modifies the label shown in a rendering tab of the memory view. + * + *

CDT adapter logic will link us to a CMemoryBlockExtension if and + * only if that block was created by specifying a memory space. In that + * case, a literal address and memory space identifier are the basis for + * the memory monitor, and the default label provided by the platform: + *

   expression : address <rendering-name> 
+ * isn't well suited. Our job is to reduce this to + *
   expression <rendering-name> 
+ * The expression ends up being the back-end provided string encoding of + * a memory space + address pair. + *

+ * @since 3.2 + */ +public class MemoryBlockLabelDecorator implements ILabelDecorator { + + /** + * The memory block we decorate the label for + */ + private CMemoryBlockExtension fMemoryBlock; + + /** + * Constructor + * @param memoryBlock the memory block we decorate the label for + */ + public MemoryBlockLabelDecorator(CMemoryBlockExtension memoryBlock) { + super(); + fMemoryBlock = memoryBlock; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ILabelDecorator#decorateImage(org.eclipse.swt.graphics.Image, java.lang.Object) + */ + public Image decorateImage(Image image, Object element) { + // we only decorate the text + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ILabelDecorator#decorateText(java.lang.String, java.lang.Object) + */ + public String decorateText(String text, Object element) { + // The rendering name is enclosed in <>. We replace everything before + // that with the memory block's expression. + int i = text.indexOf('<'); + if (i >= 0) + return fMemoryBlock.getExpression() + " " + text.substring(i); + + return text; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) + */ + public void addListener(ILabelProviderListener listener) { + // how we decorate labels is not affected by any state + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() + */ + public void dispose() { + // nothing to clean up + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String) + */ + public boolean isLabelProperty(Object element, String property) { + // how we decorate a label is not affected by any properties + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) + */ + public void removeListener(ILabelProviderListener listener) { + // how we decorate labels is not affected by any state + } + +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/Messages.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/Messages.java new file mode 100644 index 00000000000..6967161d5bf --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/Messages.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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: + * Freescale Semiconductor - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.cdt.debug.internal.ui.views.memory; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + public static String AddMemBlockDlg_enterMemSpaceAndAddr; + public static String AddMemBlockDlg_enterExpression; + public static String AddMemBlockDlg_or; + public static String AddMemBlockDlg_MonitorMemory; + + public static String AddMemBlocks_title; + public static String AddMemBlocks_noMemoryBlock; + public static String AddMemBlocks_failed; + public static String AddMemBlocks_input_invalid; + +} + diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/messages.properties b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/messages.properties new file mode 100644 index 00000000000..82f1978c9a8 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/memory/messages.properties @@ -0,0 +1,10 @@ +AddMemBlockDlg_enterMemSpaceAndAddr=Enter memory space and address +AddMemBlockDlg_enterExpression=Enter expression +AddMemBlockDlg_or=or +AddMemBlockDlg_MonitorMemory = Monitor Memory + +AddMemBlocks_title=Add Memory Monitor +AddMemBlocks_noMemoryBlock = Failed to get memory monitor. +AddMemBlocks_failed =Add Memory Monitor Failed. +AddMemBlocks_input_invalid = Input is invalid. + diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/ui/CDebugUIPlugin.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/ui/CDebugUIPlugin.java index dd475c486c1..413350ed3b0 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/ui/CDebugUIPlugin.java +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/ui/CDebugUIPlugin.java @@ -24,6 +24,7 @@ import org.eclipse.cdt.debug.internal.ui.ColorManager; import org.eclipse.cdt.debug.internal.ui.EvaluationContextManager; import org.eclipse.cdt.debug.internal.ui.IInternalCDebugUIConstants; import org.eclipse.cdt.debug.internal.ui.elements.adapters.CDebugElementAdapterFactory; +import org.eclipse.cdt.debug.internal.ui.elements.adapters.CMemoryAdapterFactory; import org.eclipse.cdt.debug.ui.sourcelookup.DefaultSourceLocator; import org.eclipse.cdt.debug.ui.sourcelookup.OldDefaultSourceLocator; import org.eclipse.cdt.internal.ui.editor.SharedTextColors; @@ -36,6 +37,8 @@ import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.model.IMemoryBlockExtension; +import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension; import org.eclipse.debug.core.model.IPersistableSourceLocator; import org.eclipse.debug.ui.ILaunchConfigurationTab; import org.eclipse.jface.dialogs.ErrorDialog; @@ -274,6 +277,10 @@ public class CDebugUIPlugin extends AbstractUIPlugin { manager.registerAdapters( elementAdapterFactory, IModuleRetrieval.class ); manager.registerAdapters( elementAdapterFactory, ICModule.class ); manager.registerAdapters( elementAdapterFactory, ICElement.class ); + + CMemoryAdapterFactory memoryAdapterFactory = new CMemoryAdapterFactory(); + manager.registerAdapters( memoryAdapterFactory, IMemoryBlockRetrievalExtension.class ); + manager.registerAdapters( memoryAdapterFactory, IMemoryBlockExtension.class ); } /*