From cc153db8ba4515daf07b94ad95a4d568058b03d0 Mon Sep 17 00:00:00 2001 From: Francois Chouinard Date: Tue, 29 Apr 2008 21:26:59 +0000 Subject: [PATCH] Implementation of the DSF Disassembly View (bug227743) --- plugins/org.eclipse.dd.dsf.debug.ui/.options | 1 + .../META-INF/MANIFEST.MF | 14 +- .../icons/disassembly.gif | Bin 0 -> 145 bytes .../plugin.properties | 19 +- .../org.eclipse.dd.dsf.debug.ui/plugin.xml | 83 +- .../debug/internal/ui/DsfDebugUIPlugin.java | 15 +- .../ui/disassembly/AbstractImageRegistry.java | 143 + .../ui/disassembly/AddressRulerColumn.java | 191 + .../disassembly/DisassemblyDropAdapter.java | 121 + .../ui/disassembly/DisassemblyEditor.java | 117 + .../DisassemblyHyperlinkDetector.java | 100 + .../disassembly/DisassemblyImageRegistry.java | 69 + .../ui/disassembly/DisassemblyMessages.java | 98 + .../DisassemblyMessages.properties | 89 + .../ui/disassembly/DisassemblyPart.java | 3442 +++++++++++++++++ .../disassembly/DisassemblyRulerColumn.java | 985 +++++ .../ui/disassembly/DisassemblyTextHover.java | 148 + .../ui/disassembly/DisassemblyView.java | 110 + .../ui/disassembly/DisassemblyViewer.java | 283 ++ .../DisassemblyViewerConfiguration.java | 131 + .../ui/disassembly/EditionFinderJob.java | 105 + .../FunctionOffsetRulerColumn.java | 69 + .../IDisassemblyHelpContextIds.java | 24 + .../ui/disassembly/IDisassemblyPart.java | 102 + .../ui/disassembly/SourceColorerJob.java | 78 + .../actions/AbstractDisassemblyAction.java | 63 + ...tractDisassemblyBreakpointRulerAction.java | 77 + .../AbstractDisassemblyRulerAction.java | 41 + ...bstractDisassemblyRulerActionDelegate.java | 167 + .../actions/ActionGotoAddress.java | 65 + .../actions/ActionGotoProgramCounter.java | 26 + .../disassembly/actions/ActionGotoSymbol.java | 59 + .../actions/ActionOpenPreferences.java | 29 + .../BreakpointPropertiesRulerAction.java | 82 + ...eakpointPropertiesRulerActionDelegate.java | 30 + .../actions/TextOperationAction.java | 58 + .../ui/disassembly/model/Addr2Line.java | 25 + .../model/AddressRangePosition.java | 66 + .../model/BreakpointsAnnotationModel.java | 229 ++ .../model/DisassemblyDocument.java | 1423 +++++++ .../model/DisassemblyPosition.java | 49 + .../model/DisassemblyWithSourcePosition.java | 52 + .../ui/disassembly/model/ErrorPosition.java | 40 + .../ui/disassembly/model/LabelPosition.java | 32 + .../model/SourceDocumentProvider.java | 116 + .../disassembly/model/SourceEditorInput.java | 35 + .../ui/disassembly/model/SourceFileInfo.java | 187 + .../ui/disassembly/model/SourcePosition.java | 50 + .../disassembly/model/SourceReadingJob.java | 80 + .../DisassemblyPreferenceConstants.java | 84 + .../DisassemblyPreferencePage.java | 313 ++ .../CSourcePresentationCreator.java | 349 ++ .../disassembly/presentation/CSourceTag.java | 207 + .../presentation/CSourceTagProvider.java | 95 + .../presentation/DisassemblyIPAnnotation.java | 79 + .../ISourcePresentationCreator.java | 35 + .../presentation/ISourceRange.java | 30 + .../disassembly/presentation/ISourceTag.java | 83 + .../presentation/ISourceTagListener.java | 24 + .../presentation/ISourceTagProvider.java | 49 + .../SourcePresentationCreatorFactory.java | 25 + .../SourceTagDamagerRepairer.java | 374 ++ .../ui/disassembly/text/IFileRider.java | 119 + .../ui/disassembly/text/REDDocument.java | 46 + .../internal/ui/disassembly/text/REDFile.java | 480 +++ .../ui/disassembly/text/REDFileRider.java | 149 + .../internal/ui/disassembly/text/REDRun.java | 149 + .../ui/disassembly/text/REDTextStore.java | 874 +++++ .../ui/disassembly/text/StringRider.java | 100 + .../ui/disassembly/text/StringTextStore.java | 70 + .../internal/ui/disassembly/util/HSL.java | 111 + .../disassembly/util/StorageEditorInput.java | 112 + .../service/command/output/MIInstruction.java | 21 +- 73 files changed, 13585 insertions(+), 11 deletions(-) create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/.options create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/icons/disassembly.gif create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyDropAdapter.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyEditor.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyHyperlinkDetector.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyImageRegistry.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyPart.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyView.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/EditionFinderJob.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/SourceColorerJob.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/Addr2Line.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/LabelPosition.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourcePosition.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/CSourcePresentationCreator.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/CSourceTag.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/CSourceTagProvider.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/DisassemblyIPAnnotation.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/ISourcePresentationCreator.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/ISourceRange.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/ISourceTag.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/ISourceTagListener.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/ISourceTagProvider.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/SourcePresentationCreatorFactory.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/presentation/SourceTagDamagerRepairer.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/IFileRider.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/REDDocument.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/REDFile.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/REDFileRider.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/REDRun.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/REDTextStore.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/StringRider.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/text/StringTextStore.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/util/HSL.java create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/util/StorageEditorInput.java diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/.options b/plugins/org.eclipse.dd.dsf.debug.ui/.options new file mode 100644 index 00000000000..b38dd1e13cc --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/.options @@ -0,0 +1 @@ +org.eclipse.dd.dsf.debug.ui/debug = false diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF index cb71e55f66e..b6129e300b3 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: Debug Services Framework Debug UI -Bundle-Vendor: Eclipse.org +Bundle-Name: %pluginName +Bundle-Vendor: %providerName Bundle-SymbolicName: org.eclipse.dd.dsf.debug.ui; singleton:=true Bundle-Version: 1.0.0.qualifier Bundle-Activator: org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin @@ -18,7 +18,15 @@ Require-Bundle: org.eclipse.ui, org.eclipse.dd.dsf.ui, org.eclipse.dd.dsf.debug, org.eclipse.cdt.core, - org.eclipse.cdt.debug.ui + org.eclipse.cdt.debug.core, + org.eclipse.cdt.debug.ui, + org.eclipse.jface.text;bundle-version="3.4.0", + org.eclipse.ui.editors;bundle-version="3.4.0", + org.eclipse.ui.workbench.texteditor;bundle-version="3.4.0", + org.eclipse.ui.ide;bundle-version="3.4.0", + org.eclipse.cdt.ui;bundle-version="5.0.0", + org.eclipse.core.expressions;bundle-version="3.4.0", + org.eclipse.core.filesystem;bundle-version="1.2.0" Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel, diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/icons/disassembly.gif b/plugins/org.eclipse.dd.dsf.debug.ui/icons/disassembly.gif new file mode 100644 index 0000000000000000000000000000000000000000..34f5290474b745d4113b3405d617c6606d012a82 GIT binary patch literal 145 zcmZ?wbhEHb6krfw*v!CSZ$IBYe!qSF{$-~=9Jq7f|Ns9Cc!AeDh9;!5RQrpe}6y literal 0 HcmV?d00001 diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/plugin.properties b/plugins/org.eclipse.dd.dsf.debug.ui/plugin.properties index d7b098572ef..20d921a68b9 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/plugin.properties +++ b/plugins/org.eclipse.dd.dsf.debug.ui/plugin.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2006 Wind River Systems and others. +# Copyright (c) 2006, 2008 Wind River 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 @@ -8,6 +8,21 @@ # Contributors: # Wind River Systems - initial API and implementation ############################################################################### -pluginName=DSDP/DD Debugger Services Framework (DSF) Debug UI +pluginName=Debug Services Framework Debug UI providerName=Eclipse.org +# disassembly +disassemblyPreferencePage.name = DSF Disassembly +disassemblyView.name= DSF Disassembly + +command.gotoPC.name=Go to Program Counter +command.gotoPC.description=Navigate to current program counter +command.gotoAddress.name=Go to Address... +command.gotoAddress.description=Navigate to address +command.gotoSymbol.name=Go to Symbol... +command.gotoSymbol.description=Navigate to symbolic address + +commandContext.name= In DSF Disassembly +commandContext.description= When debugging in assembly mode + +action.breakpointProperties.label = Breakpoint Properties... diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml b/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml index c7dec8bb485..21b6f155b7c 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml +++ b/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml @@ -278,5 +278,86 @@ id="org.eclipse.dd.dsf.debug.ui.viewmodel.moduleDetailPaneFactory"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/DsfDebugUIPlugin.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/DsfDebugUIPlugin.java index 5e20f049521..144b4d90fa8 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/DsfDebugUIPlugin.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/DsfDebugUIPlugin.java @@ -1,5 +1,6 @@ package org.eclipse.dd.dsf.debug.internal.ui; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourceDocumentProvider; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; @@ -17,8 +18,11 @@ public class DsfDebugUIPlugin extends AbstractUIPlugin { private static DsfDebugUIPlugin plugin; // BundleContext of this plugin - private static BundleContext fgBundleContext; - + private static BundleContext fgBundleContext; + + // The document provider for source documents in the disassembly. + private SourceDocumentProvider fSourceDocumentProvider; + /** * The constructor */ @@ -35,6 +39,7 @@ public class DsfDebugUIPlugin extends AbstractUIPlugin { plugin = this; fgBundleContext = context; + fSourceDocumentProvider = new SourceDocumentProvider(); } /* @@ -43,6 +48,8 @@ public class DsfDebugUIPlugin extends AbstractUIPlugin { */ @Override public void stop(BundleContext context) throws Exception { + fSourceDocumentProvider.dispose(); + fSourceDocumentProvider = null; plugin = null; super.stop(context); } @@ -75,4 +82,8 @@ public class DsfDebugUIPlugin extends AbstractUIPlugin { public static ImageDescriptor getImageDescriptor(String path) { return imageDescriptorFromPlugin(PLUGIN_ID, path); } + + public static SourceDocumentProvider getSourceDocumentProvider() { + return getDefault().fSourceDocumentProvider; + } } diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java new file mode 100644 index 00000000000..2f4aedcb834 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Image; +import org.osgi.framework.Bundle; + + +/** + * Abstract image registry that allows for defining fallback paths for images. + */ +public abstract class AbstractImageRegistry extends ImageRegistry { + private HashMap fPlugins = new HashMap(); + private HashMap fLocations = new HashMap(); + private URL fBaseUrl; + + protected AbstractImageRegistry(Plugin plugin) { + fBaseUrl = plugin.getBundle().getEntry("/"); //$NON-NLS-1$ + } + + /** + * Defines the key for a local image, that must be found below the icons directory + * in the plugin. + * @param key Key by which the image can be referred by. + * @param dir Directory relative to icons/ + * @param name The name of the file defining the icon. The name will be used as + * key. + */ + protected void localImage(String key, String dir, String name) { + if (dir== null || dir.equals(""))//$NON-NLS-1$ + fLocations.put(key, new String[] {"icons/" + name}); //$NON-NLS-1$ + else + fLocations.put(key, new String[] {"icons/" + dir + "/" + name}); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Defines the key for a non-local image, that must be found below the icons directory + * of some plugin. + * @param key Key by which the image can be referred by. + * @param plugin The plugin id, where the icon is searched. + * @param dirs A couple of directories below icons/ in the plugin. If loading fails, + * the next dir will be taken as fallback. + * @param name The name of the file defining the icon. The name will be used as + * key. + */ + protected void externalImage(String key, String plugin, String[] dirs, String name) { + if (plugin != null) { + fPlugins.put(key, plugin); + } + String[] locations = new String[dirs.length]; + for (int i = 0; i < dirs.length; i++) { + String dir = dirs[i]; + if (dir== null || dir.equals(""))//$NON-NLS-1$ + locations[i] = "icons/" + name; //$NON-NLS-1$ + else + locations[i] = "icons/" + dir + "/" + name; //$NON-NLS-1$ //$NON-NLS-2$ + } + fLocations.put(key, locations); + } + + // overrider + @Override + final public Image get(String key) { + Image i = super.get(key); + if (i != null) { + return i; + } + + ImageDescriptor d = createFileImageDescriptor(key); + if (d != null) { + put(key, d); + return super.get(key); + } + return null; + } + + // overrider + @Override + final public ImageDescriptor getDescriptor(String key) { + ImageDescriptor d = super.getDescriptor(key); + if (d != null) { + return d; + } + + d = createFileImageDescriptor(key); + if (d != null) { + put(key, d); + return d; + } + return null; + } + + private ImageDescriptor createFileImageDescriptor(String key) { + URL url = fBaseUrl; + String pluginId = fPlugins.get(key); + if (pluginId != null) { + Bundle bundle= Platform.getBundle(pluginId); + if (bundle != null) { + url = bundle.getEntry("/"); //$NON-NLS-1$ + } + } + String[] locations= fLocations.get(key); + if (locations != null) { + for (int i = 0; i < locations.length; i++) { + String loc = locations[i]; + URL full; + try { + full = new URL(url, loc); + ImageDescriptor candidate = ImageDescriptor.createFromURL(full); + if (candidate != null && candidate.getImageData() != null) { + return candidate; + } + } catch (MalformedURLException e) { + DsfDebugUIPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, "Malformed Icon URL", e)); //$NON-NLS-1$ + } catch (SWTException e) { + // try the next one. + } + } + } + return null; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java new file mode 100644 index 00000000000..df91c158d50 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.math.BigInteger; + +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.AddressRangePosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourceFileInfo; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourcePosition; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.source.IAnnotationHover; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.IVerticalRulerInfo; +import org.eclipse.jface.text.source.IVerticalRulerInfoExtension; +import org.eclipse.jface.text.source.IVerticalRulerListener; +import org.eclipse.swt.SWT; + +/** + * A vertical ruler column to display the instruction address. + */ +public class AddressRulerColumn extends DisassemblyRulerColumn implements IVerticalRulerInfo, IVerticalRulerInfoExtension, IAnnotationHover { + + private int fRadix; + private boolean fShowRadixPrefix; + private String fRadixPrefix; + private int fNumberOfDigits; + private int fAddressSize; + + /** + * Default constructor. + */ + public AddressRulerColumn() { + super(SWT.LEFT); + setShowRadixPrefix(true); + setAddressSize(32); + setRadix(16); + } + + /* + * @see com.windriver.ide.disassembly.views.DisassemblyRulerColumn#createDisplayString(int) + */ + @Override + protected String createDisplayString(int line) { + DisassemblyDocument doc = (DisassemblyDocument)getParentRuler().getTextViewer().getDocument(); + int offset; + try { + offset = doc.getLineOffset(line); + AddressRangePosition pos = doc.getDisassemblyPosition(offset); + if (pos != null && pos.length > 0 && pos.offset == offset) { + if (pos.fValid) { + return getAddressText(pos.fAddressOffset); + } else { + return DOTS.substring(0, computeNumberOfCharacters()); + } + } + SourcePosition srcPos = doc.getSourcePosition(offset); + if (srcPos != null && srcPos.fValid && srcPos.length > 0) { + int srcLine; + int nLines; + if (srcPos.fFileInfo.fSource == null) { + srcLine = srcPos.fLine; + nLines = srcLine+1; + } else { + int delta = offset-srcPos.offset; + int baseOffset = srcPos.fFileInfo.fSource.getLineOffset(srcPos.fLine); + srcLine = srcPos.fFileInfo.fSource.getLineOfOffset(baseOffset+delta); + nLines = srcPos.fFileInfo.fSource.getNumberOfLines(); + } + String digitStr = Integer.toString(srcLine+1); + int maxDigits = (int)(Math.log(nLines)/Math.log(10))+1; + return SPACES.substring(0, maxDigits-digitStr.length())+digitStr; + } + } catch (BadLocationException e) { + // silently ignored + } + return ""; //$NON-NLS-1$ + } + + /* + * @see com.windriver.ide.disassembly.views.DisassemblyRulerColumn#computeNumberOfCharacters() + */ + @Override + protected int computeNumberOfCharacters() { + return fNumberOfDigits + (fRadixPrefix != null ? fRadixPrefix.length() : 0) + 1; + } + + public void setAddressSize(int bits) { + fAddressSize= bits; + calculateNumberOfDigits(); + } + + public void setRadix(int radix) { + fRadix= radix; + calculateNumberOfDigits(); + setShowRadixPrefix(fShowRadixPrefix); + } + + private void calculateNumberOfDigits() { + fNumberOfDigits= BigInteger.ONE.shiftLeft(fAddressSize).subtract(BigInteger.ONE).toString(fRadix).length(); + } + + public void setShowRadixPrefix(boolean showRadixPrefix) { + fShowRadixPrefix = showRadixPrefix; + if (!fShowRadixPrefix) { + fRadixPrefix = null; + } else if (fRadix == 16) { + fRadixPrefix = "0x"; //$NON-NLS-1$ + } else if (fRadix == 8) { + fRadixPrefix = "0"; //$NON-NLS-1$ + } else { + fRadixPrefix = null; + } + } + + private String getAddressText(BigInteger address) { + StringBuffer buf = new StringBuffer(fNumberOfDigits + 3); + if (fRadixPrefix != null) { + buf.append(fRadixPrefix); + } + String str = address.toString(fRadix); + for (int i=str.length(); i fStore = new ArrayList(); + + private static String add(String plugin, String[] dirs, String name) { + String key = plugin+'/'+dirs[0]+'/'+name; + fStore.add(new Object[] {key, plugin, dirs, name}); + return key; + } + + private static final String ORG_ECLIPSE_DEBUG_UI_PLUGIN_ID = "org.eclipse.debug.ui"; //$NON-NLS-1$ + private static final String ORG_ECLIPSE_UI_PLUGIN_ID = "org.eclipse.ui"; //$NON-NLS-1$ + + public static final String ICON_ToggleBreakpoint = add(ORG_ECLIPSE_DEBUG_UI_PLUGIN_ID, new String[] { "full/obj16"}, "brkp_obj.gif"); //$NON-NLS-1$ //$NON-NLS-2$ + public static final String ICON_Refresh_enabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/elcl16"}, "refresh_nav.gif"); //$NON-NLS-1$ //$NON-NLS-2$ + public static final String ICON_Refresh_disabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/dlcl16"}, "refresh_nav.gif"); //$NON-NLS-1$ //$NON-NLS-2$ + public static final String ICON_Copy_enabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/etool16"}, "copy_edit.gif"); //$NON-NLS-1$ //$NON-NLS-2$ + public static final String ICON_Copy_disabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/dtool16"}, "copy_edit.gif"); //$NON-NLS-1$ //$NON-NLS-2$ + + private static DisassemblyImageRegistry INSTANCE= new DisassemblyImageRegistry(DsfDebugUIPlugin.getDefault()); + + DisassemblyImageRegistry(Plugin plugin) { + super(plugin); + initialize(); + } + + void initialize() { + for (Iterator iter = fStore.iterator(); iter.hasNext();) { + Object[] element = iter.next(); + if (element.length == 2) { + String dir= (String) element[0]; + String name= (String) element[1]; + localImage(name, dir, name); + } else { + String key = (String) element[0]; + String plugin= (String) element[1]; + String[] dirs= (String[]) element[2]; + String name= (String) element[3]; + externalImage(key, plugin, dirs, name); + } + } + } + + public static ImageDescriptor getImageDescriptor(String key) { + return INSTANCE.getDescriptor(key); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java new file mode 100644 index 00000000000..241f34de10d --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import org.eclipse.osgi.util.NLS; + +public final class DisassemblyMessages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages";//$NON-NLS-1$ + + private DisassemblyMessages() { + // Do not instantiate + } + + public static String Disassembly_action_ShowAddresses_label; + public static String Disassembly_action_ShowFunctionOffsets_label; + public static String Disassembly_action_ShowDisassembly_label; + public static String Disassembly_action_ShowSource_label; + public static String Disassembly_action_ShowSymbols_label; + public static String Disassembly_action_ShowSimplified_label; + public static String Disassembly_action_SourceSteppingMode_error; + public static String Disassembly_action_SourceSteppingMode_label; + public static String Disassembly_action_AssemblySteppingMode_label; + public static String Disassembly_action_RunToHere_label; + public static String Disassembly_action_SetPCToHere_label; + public static String Disassembly_action_GotoPC_label; + public static String Disassembly_action_GotoPC_tooltip; + public static String Disassembly_action_GotoAddress_label; + public static String Disassembly_action_GotoSymbol_label; + public static String Disassembly_action_Copy_label; + public static String Disassembly_action_SelectAll_label; + public static String Disassembly_action_BreakpointProperties_label; + public static String Disassembly_action_RemoveBreakpoint_label; + public static String Disassembly_action_AddBreakpoint_label; + public static String Disassembly_action_AddHWBreakpoint_label; + public static String Disassembly_action_AddTracepoint_label; + public static String Disassembly_action_DisableBreakpoint_label; + public static String Disassembly_action_EnableBreakpoint_label; + public static String Disassembly_action_WatchExpression_label; + public static String Disassembly_action_ShowInMemory_label; + public static String Disassembly_action_RefreshView_label; + public static String Disassembly_action_OpenPreferences_label; + public static String Disassembly_GotoAddressDialog_title; + public static String Disassembly_GotoAddressDialog_label; + public static String Disassembly_GotoAddressDialog_error_invalid_address; + public static String Disassembly_GotoAddressDialog_error_not_a_number; + public static String Disassembly_GotoSymbolDialog_title; + public static String Disassembly_GotoSymbolDialog_label; + public static String Disassembly_message_notConnected; + public static String Disassembly_log_error_retrieveFrameAddress; + public static String Disassembly_log_error_locateFile; + public static String Disassembly_log_error_accessLineInfo; + public static String Disassembly_log_error_noFileInfo; + public static String Disassembly_log_error_fileTooLarge; + public static String Disassembly_log_error_readFile; + public static String Disassembly_log_error_createVersion; + public static String Disassembly_log_error_retrieveDisassembly; + public static String Disassembly_log_error_showDisassembly; + public static String Disassembly_log_error_invalidSymbol; + public static String DisassemblyPreferencePage_startAddress; + public static String DisassemblyPreferencePage_endAddress; + public static String DisassemblyPreferencePage_addressRadix; + public static String DisassemblyPreferencePage_instructionRadix; + public static String DisassemblyPreferencePage_showAddressRadix; + public static String DisassemblyPreferencePage_showSource; + public static String DisassemblyPreferencePage_showSymbols; + public static String DisassemblyPreferencePage_simplifiedMnemonics; + public static String DisassemblyPreferencePage_error_not_a_number; + public static String DisassemblyPreferencePage_error_negative_number; + public static String DisassemblyPreferencePage_radix_octal; + public static String DisassemblyPreferencePage_radix_decimal; + public static String DisassemblyPreferencePage_radix_hexadecimal; + public static String DisassemblyPreferencePage_showFunctionOffsets; + public static String DisassemblyPreferencePage_showAddress; + public static String DisassemblyPreferencePage_useSourceOnlyMode; + public static String DisassemblyPreferencePage_useSourceOnlyMode_noteTtitle; + public static String DisassemblyPreferencePage_useSourceOnlyMode_noteMessage; + public static String DisassemblyPreferencePage_avoidReadBeforePC; + public static String DisassemblyIPAnnotation_primary; + public static String DisassemblyIPAnnotation_secondary; + public static String SourceReadingJob_name; + public static String SourceColorerJob_name; + public static String EditionFinderJob_name; + public static String EditionFinderJob_task_get_timestamp; + public static String EditionFinderJob_task_search_history; + + static { + NLS.initializeMessages(BUNDLE_NAME, DisassemblyMessages.class); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties new file mode 100644 index 00000000000..479808236de --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties @@ -0,0 +1,89 @@ +########################################################################## +# Copyright (c) 2007, 2008 Wind River 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: +# Wind River Systems - initial API and implementation +########################################################################## + +Disassembly_action_ShowAddresses_label=Show Addresses +Disassembly_action_ShowFunctionOffsets_label=Show Function Offsets +Disassembly_action_ShowDisassembly_label=Show Disassembly of Source +Disassembly_action_ShowSource_label=Show Source +Disassembly_action_ShowSymbols_label=Show Symbols +Disassembly_action_ShowSimplified_label=Show Simplified Instructions +Disassembly_action_SourceSteppingMode_error=Cannot open editor for file +Disassembly_action_SourceSteppingMode_label=Source Stepping Mode +Disassembly_action_AssemblySteppingMode_label=Assembly Stepping Mode +Disassembly_action_RunToHere_label=Run to Here +Disassembly_action_SetPCToHere_label=Set PC to Here +Disassembly_action_GotoPC_label=Go to Program Counter +Disassembly_action_GotoPC_tooltip=Go to Current Program Counter +Disassembly_action_GotoAddress_label=Go to Address... +Disassembly_action_GotoSymbol_label=Go to Symbol... +Disassembly_action_Copy_label=&Copy +Disassembly_action_SelectAll_label=Select &All +Disassembly_action_BreakpointProperties_label=Breakpoint Properties... +Disassembly_action_RemoveBreakpoint_label=Remove Breakpoint +Disassembly_action_AddBreakpoint_label=Add Breakpoint +Disassembly_action_AddHWBreakpoint_label=Add Hardware Breakpoint +Disassembly_action_AddTracepoint_label=Add Tracepoint... +Disassembly_action_DisableBreakpoint_label=Disable Breakpoint +Disassembly_action_EnableBreakpoint_label=Enable Breakpoint +Disassembly_action_WatchExpression_label=Watch Expression +Disassembly_action_ShowInMemory_label=Show In Memory View +Disassembly_action_RefreshView_label=Re&fresh View +Disassembly_action_OpenPreferences_label=&Preferences... + +Disassembly_GotoAddressDialog_title=Go to Address +Disassembly_GotoAddressDialog_label=Address: +Disassembly_GotoAddressDialog_error_invalid_address=Invalid address +Disassembly_GotoAddressDialog_error_not_a_number=Not a valid number format + +Disassembly_GotoSymbolDialog_title=Go to Symbol +Disassembly_GotoSymbolDialog_label=Symbol: + +Disassembly_message_notConnected=No debug context + +Disassembly_log_error_retrieveFrameAddress=Error retrieving frame address +Disassembly_log_error_locateFile=Unable to locate file:\ +Disassembly_log_error_accessLineInfo=Error accessing line information for:\ +Disassembly_log_error_noFileInfo=Debug information not found for:\ +Disassembly_log_error_fileTooLarge=Source file is too large to retrieve line information:\ +Disassembly_log_error_readFile=Cannot read source file:\ +Disassembly_log_error_createVersion=Cannot create version +Disassembly_log_error_retrieveDisassembly=Cannot retrieve disassembly for:\ +Disassembly_log_error_showDisassembly=Error opening Disassembly +Disassembly_log_error_invalidSymbol=Cannot evaluate symbolic address ''{0}'' + +DisassemblyPreferencePage_startAddress=Start address +DisassemblyPreferencePage_endAddress=End address +DisassemblyPreferencePage_addressRadix=Address display format +DisassemblyPreferencePage_instructionRadix=Instruction display format +DisassemblyPreferencePage_showAddressRadix=Force radix prefixes +DisassemblyPreferencePage_showSource=Show source +DisassemblyPreferencePage_showSymbols=Show symbols +DisassemblyPreferencePage_simplifiedMnemonics=Use simplified instruction mnemonics +DisassemblyPreferencePage_error_not_a_number=Not a valid number format +DisassemblyPreferencePage_error_negative_number=Address cannot be negative +DisassemblyPreferencePage_radix_octal=Octal +DisassemblyPreferencePage_radix_decimal=Decimal +DisassemblyPreferencePage_radix_hexadecimal=Hexadecimal +DisassemblyPreferencePage_showFunctionOffsets=Show function offsets +DisassemblyPreferencePage_showAddress=Show instruction address +DisassemblyPreferencePage_useSourceOnlyMode=Use Disassembly Viewer when debugging in source stepping mode +DisassemblyPreferencePage_useSourceOnlyMode_noteTtitle=Note: +DisassemblyPreferencePage_useSourceOnlyMode_noteMessage=When this option is enabled, the Disassembly Viewer will be used to display source locations in a special "source-only" mode, instead of using the normal Source Editor. +DisassemblyPreferencePage_avoidReadBeforePC=Do not disassemble code before current program counter + +DisassemblyIPAnnotation_primary=Debug Current Instruction Pointer +DisassemblyIPAnnotation_secondary=Debug Call Stack + +SourceReadingJob_name=Reading source file +SourceColorerJob_name=Coloring source file +EditionFinderJob_name=Finding best match for source file +EditionFinderJob_task_get_timestamp=Retrieving module timestamp +EditionFinderJob_task_search_history=Searching local history diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyPart.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyPart.java new file mode 100644 index 00000000000..fef238139e6 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyPart.java @@ -0,0 +1,3442 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.io.File; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.debug.core.CDIDebugModel; +import org.eclipse.cdt.debug.core.model.ICBreakpoint; +import org.eclipse.cdt.internal.ui.dnd.TextViewerDragAdapter; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.AbstractDisassemblyAction; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.ActionGotoAddress; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.ActionGotoProgramCounter; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.ActionGotoSymbol; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.ActionOpenPreferences; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.TextOperationAction; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.Addr2Line; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.AddressRangePosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.BreakpointsAnnotationModel; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyPosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.ErrorPosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.LabelPosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourceFileInfo; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourcePosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.preferences.DisassemblyPreferenceConstants; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.presentation.DisassemblyIPAnnotation; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.util.HSL; +import org.eclipse.dd.dsf.debug.service.IDisassembly; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IInstruction; +import org.eclipse.dd.dsf.debug.service.IMixedInstruction; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.ISourceLookup; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.dd.dsf.debug.service.IDisassembly.IDisassemblyDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.dd.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMData; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.DsfSession.SessionEndedListener; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.ISuspendResume; +import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.actions.IRunToLineTarget; +import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.commands.ActionHandler; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.IFindReplaceTarget; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.ITextPresentationListener; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.ITextViewerExtension; +import org.eclipse.jface.text.IViewportListener; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationModel; +import org.eclipse.jface.text.source.AnnotationRulerColumn; +import org.eclipse.jface.text.source.CompositeRuler; +import org.eclipse.jface.text.source.IAnnotationAccess; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IAnnotationModelExtension; +import org.eclipse.jface.text.source.IOverviewRuler; +import org.eclipse.jface.text.source.ISharedTextColors; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.IVerticalRuler; +import org.eclipse.jface.text.source.IVerticalRulerColumn; +import org.eclipse.jface.text.source.IVerticalRulerExtension; +import org.eclipse.jface.text.source.IVerticalRulerInfo; +import org.eclipse.jface.text.source.OverviewRuler; +import org.eclipse.jface.text.source.SourceViewerConfiguration; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.handlers.IHandlerActivation; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.ide.IGotoMarker; +import org.eclipse.ui.part.WorkbenchPart; +import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; +import org.eclipse.ui.texteditor.AnnotationPreference; +import org.eclipse.ui.texteditor.ChainedPreferenceStore; +import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; +import org.eclipse.ui.texteditor.ITextEditorActionConstants; +import org.eclipse.ui.texteditor.IUpdate; +import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds; +import org.eclipse.ui.texteditor.MarkerAnnotationPreferences; +import org.eclipse.ui.texteditor.SimpleMarkerAnnotation; +import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; + +/** + * DisassemblyPart + */ +public abstract class DisassemblyPart extends WorkbenchPart implements IDisassemblyPart, IViewportListener, ITextPresentationListener { + + private final static boolean DEBUG = DsfDebugUIPlugin.getDefault().isDebugging(); + + /** + * Annotation model attachment key for breakpoint annotations. + */ + private final static String BREAKPOINT_ANNOTATIONS= "breakpoints"; //$NON-NLS-1$ + + private final static BigInteger PC_UNKNOWN = BigInteger.valueOf(-1); + private final static BigInteger PC_RUNNING = BigInteger.valueOf(-2); + + /** Preference key for highlighting current line. */ + private final static String CURRENT_LINE = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE; + /** Preference key for highlight color of current line. */ + private final static String CURRENT_LINE_COLOR = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR; + + /** The width of the vertical ruler. */ + protected final static int VERTICAL_RULER_WIDTH = 12; + + /** High water mark for cache */ + private final static int fgHighWaterMark = 500; + /** Low water mark for cache */ + private final static int fgLowWaterMark = 100; + + private static final String COMMAND_ID_GOTO_ADDRESS = "org.eclipse.dd.dsf.debug.ui.disassembly.commands.gotoAddress"; //$NON-NLS-1$ + private static final String COMMAND_ID_GOTO_PC = "org.eclipse.dd.dsf.debug.ui.disassembly.commands.gotoPC"; //$NON-NLS-1$ + private static final String COMMAND_ID_GOTO_SYMBOL = "org.eclipse.dd.dsf.debug.ui.disassembly.commands.gotoSymbol"; //$NON-NLS-1$ +// private static final String COMMAND_ID_TOGGLE_BREAKPOINT = "org.eclipse.debug.ui.commands.ToggleBreakpoint"; //$NON-NLS-1$ +// private static final String COMMAND_ID_RUN_TO_LINE = "org.eclipse.debug.ui.commands.RunToLine"; //$NON-NLS-1$ +// private static final String COMMAND_ID_TOGGLE_STEPPING_MODE = "org.eclipse.dd.dsf.debug.ui.debug.ui.menu.showDisassemblyAction"; //$NON-NLS-1$ + + private static final String KEY_BINDING_CONTEXT_DISASSEMBLY = "org.eclipse.dd.dsf.debug.ui.disassembly.context"; //$NON-NLS-1$ + + protected DisassemblyViewer fViewer; + + protected AbstractDisassemblyAction fActionGotoPC; + protected AbstractDisassemblyAction fActionGotoAddress; + private AbstractDisassemblyAction fActionGotoSymbol; + private AbstractDisassemblyAction fActionToggleBreakpoint; + protected AbstractDisassemblyAction fActionToggleSource; + private AbstractDisassemblyAction fActionToggleFunctionColumn; + private AbstractDisassemblyAction fActionToggleSymbols; + private AbstractDisassemblyAction fActionRefreshView; + private Action fActionOpenPreferences; + private AbstractDisassemblyAction fActionToggleAddressColumn; + private AbstractDisassemblyAction fActionToggleBreakpointEnablement; + + protected DisassemblyDocument fDocument; + private IAnnotationAccess fAnnotationAccess; + private AnnotationRulerColumn fAnnotationRulerColumn; + private MarkerAnnotationPreferences fAnnotationPreferences; + private IPreferenceStore fPreferenceStore; + private IOverviewRuler fOverviewRuler; + private final ListenerList fRulerContextMenuListeners= new ListenerList(ListenerList.IDENTITY); + private SourceViewerDecorationSupport fDecorationSupport; + private Font fFont; + private IVerticalRuler fVerticalRuler; + private IFindReplaceTarget fFindReplaceTarget; + private IPropertyChangeListener fPropertyChangeListener= new PropertyChangeListener(); + private Color fInstructionColor; + private Color fErrorColor; + private Color fSourceColor; + private Color fLabelColor; + private Control fRedrawControl; + private Point fContextClickLocation; + private RGB fPCAnnotationRGB; + private Composite fComposite; + + private DropTarget fDropTarget; + private DragSource fDragSource; + private TextViewerDragAdapter fDragSourceAdapter; + private DisassemblyDropAdapter fDropTargetAdapter; + + private FunctionOffsetRulerColumn fOpcodeRulerColumn; + private AddressRulerColumn fAddressRulerColumn; + + private BigInteger fStartAddress; + private BigInteger fEndAddress; + private int fAddressSize= 32; + + private volatile boolean fUpdatePending; + private BigInteger fPCAddress; + private BigInteger fGotoAddressPending= PC_UNKNOWN; + private BigInteger fFocusAddress= PC_UNKNOWN; + private int fBufferZone; + private IExecutionDMContext fTargetContext; + private String fDebugSessionId; + private int fTargetFrame; + private DisassemblyIPAnnotation fPCAnnotation; + private DisassemblyIPAnnotation fSecondaryPCAnnotation; + private boolean fPCAnnotationUpdatePending; + private ArrayList fPendingPCUpdates = new ArrayList(5); + private Position fScrollPos; + private int fScrollLine; + private Position fFocusPos; + private BigInteger fFrameAddress= PC_UNKNOWN; + protected Map fGlobalActions = new HashMap(); + private List fSelectionActions = new ArrayList(); + private List fStateDependentActions = new ArrayList(); + private boolean fSourceOnlyMode; + private boolean fShowSource; + private boolean fShowOpcodes; + private boolean fShowSymbols; + private Map fFile2Storage = new HashMap(); + private boolean fShowDisassembly; + private LinkedList fPCHistory = new LinkedList(); + private int fPCHistorySizeMax = 4; + private boolean fGotoFramePending; + + private String fPCAnnotationColorKey; + + private ArrayList fRunnableQueue = new ArrayList(); + + protected IPartListener2 fPartListener = + new IPartListener2() { + public void partActivated(IWorkbenchPartReference partRef) { + } + public void partBroughtToTop(IWorkbenchPartReference partRef) { + } + public void partClosed(IWorkbenchPartReference partRef) { + } + public void partDeactivated(IWorkbenchPartReference partRef) { + } + public void partOpened(IWorkbenchPartReference partRef) { + } + public void partHidden(IWorkbenchPartReference partRef) { + if (partRef.getPart(false) == DisassemblyPart.this) { + setActive(false); + } + } + public void partVisible(IWorkbenchPartReference partRef) { + if (partRef.getPart(false) == DisassemblyPart.this) { + setActive(true); + } + } + public void partInputChanged(IWorkbenchPartReference partRef) { + } + }; + + private boolean fActive = true; + private boolean fDoPendingPosted; + private boolean fUpdateBeforeFocus; + + private boolean fRefreshAll; + private IMarker fGotoMarkerPending; + private boolean fUpdateTitlePending; + private boolean fRefreshViewPending; + private boolean fUpdateSourcePending; + + private ArrayList fHandlerActivations; + private IContextActivation fContextActivation; + + private DsfServicesTracker fServicesTracker; + private IFrameDMContext fTargetFrameContext; + protected IFrameDMData fTargetFrameData; + + + private final class ActionRefreshView extends AbstractDisassemblyAction { + public ActionRefreshView() { + super(DisassemblyPart.this); + setText(DisassemblyMessages.Disassembly_action_RefreshView_label); + setImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Refresh_enabled)); + setDisabledImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Refresh_disabled)); + } + @Override + public void run() { + refreshView(10); + } + } + + private final class ActionToggleAddressColumn extends AbstractDisassemblyAction { + ActionToggleAddressColumn () { + super(DisassemblyPart.this); + setText(DisassemblyMessages.Disassembly_action_ShowAddresses_label); + } + @Override + public void run() { + IPreferenceStore store = DsfDebugUIPlugin.getDefault().getPreferenceStore(); + store.setValue(DisassemblyPreferenceConstants.SHOW_ADDRESS_RULER, !isAddressRulerVisible()); + } + @Override + public void update() { + setChecked(isAddressRulerVisible()); + } + } + + private final class ActionToggleFunctionColumn extends AbstractDisassemblyAction { + ActionToggleFunctionColumn() { + super(DisassemblyPart.this); + setText(DisassemblyMessages.Disassembly_action_ShowFunctionOffsets_label); + } + @Override + public void run() { + IPreferenceStore store = DsfDebugUIPlugin.getDefault().getPreferenceStore(); + store.setValue(DisassemblyPreferenceConstants.SHOW_FUNCTION_OFFSETS, !isOpcodeRulerVisible()); + } + @Override + public void update() { + setChecked(isOpcodeRulerVisible()); + } + } + + private final class ActionToggleBreakpoint extends AbstractDisassemblyAction { + private IBreakpoint fBreakpoint; + private int fLine; + public ActionToggleBreakpoint() { + super(DisassemblyPart.this); + setText(DisassemblyMessages.Disassembly_action_AddBreakpoint_label); + setImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_ToggleBreakpoint)); + } + @Override + public void run() { + try { + if (fBreakpoint != null) { + fBreakpoint.delete(); + } else { + insertBreakpoint(fLine, false); + } + } catch (CoreException e) { + DsfDebugUIPlugin.getDefault().getLog().log(e.getStatus()); + } + } + @Override + public void update() { + super.update(); + if (isEnabled()) { + fLine = fVerticalRuler.getLineOfLastMouseButtonActivity(); + IBreakpoint[] bps = getBreakpointsAtLine(fLine); + if (bps == null) { + fBreakpoint = null; + setText(DisassemblyMessages.Disassembly_action_AddBreakpoint_label); + } else { + fBreakpoint = bps[0]; + setText(DisassemblyMessages.Disassembly_action_RemoveBreakpoint_label); + } + } + } + } + + private final class ActionToggleBreakpointEnablement extends AbstractDisassemblyAction { + private IBreakpoint fBreakpoint; + public ActionToggleBreakpointEnablement() { + super(DisassemblyPart.this); + setText(DisassemblyMessages.Disassembly_action_EnableBreakpoint_label); + } + @Override + public void run() { + try { + fBreakpoint.setEnabled(!fBreakpoint.isEnabled()); + } catch (CoreException e) { + internalError(e); + } + } + @Override + public void update() { + super.update(); + if (isEnabled()) { + int line = fVerticalRuler.getLineOfLastMouseButtonActivity(); + IBreakpoint[] bps = getBreakpointsAtLine(line); + if (bps == null || bps.length == 0) { + setEnabled(false); + } else { + fBreakpoint = bps[0]; + try { + if (fBreakpoint.isEnabled()) { + setText(DisassemblyMessages.Disassembly_action_DisableBreakpoint_label); + } else { + setText(DisassemblyMessages.Disassembly_action_EnableBreakpoint_label); + } + } catch (CoreException e) { + setEnabled(false); + } + } + } + } + } + + private final class ActionToggleSource extends AbstractDisassemblyAction { + public ActionToggleSource() { + super(DisassemblyPart.this); + setText(DisassemblyMessages.Disassembly_action_ShowSource_label); + } + @Override + public void run() { + IPreferenceStore store = DsfDebugUIPlugin.getDefault().getPreferenceStore(); + boolean showSourceEnabled = store.getBoolean(DisassemblyPreferenceConstants.SHOW_SOURCE); + if (showSourceEnabled == fShowSource) { + store.setValue(DisassemblyPreferenceConstants.SHOW_SOURCE, !fShowSource); + } else { + sourceModeChanged(!fShowSource); + } + } + @Override + public void update() { + super.update(); + if (isEnabled()) { + setEnabled(fShowDisassembly); + } + setChecked(fShowSource); + } + } + + private final class ActionToggleSymbols extends AbstractDisassemblyAction { + public ActionToggleSymbols() { + super(DisassemblyPart.this); + setText(DisassemblyMessages.Disassembly_action_ShowSymbols_label); + } + @Override + public void run() { + IPreferenceStore store = DsfDebugUIPlugin.getDefault().getPreferenceStore(); + store.setValue(DisassemblyPreferenceConstants.SHOW_SYMBOLS, !fShowSymbols); + } + @Override + public void update() { + super.update(); + setChecked(fShowSymbols); + } + } + + /** + * Internal property change listener for handling changes in the + * preferences. + */ + class PropertyChangeListener implements IPropertyChangeListener { + /* + * @see IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) + */ + public void propertyChange(PropertyChangeEvent event) { + handlePreferenceStoreChanged(event); + } + } + + + /** + * The constructor. + */ + public DisassemblyPart() { + fAnnotationPreferences = new MarkerAnnotationPreferences(); + setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore[] { + DsfDebugUIPlugin.getDefault().getPreferenceStore(), EditorsUI.getPreferenceStore() })); + fPCAddress = fFrameAddress = PC_RUNNING; + fTargetFrame = -1; + fBufferZone = 32; + fPCAnnotation = new DisassemblyIPAnnotation(true, 0); + fSecondaryPCAnnotation = new DisassemblyIPAnnotation(false, 0); + IPreferenceStore prefs = getPreferenceStore(); + fStartAddress = new BigInteger(prefs.getString(DisassemblyPreferenceConstants.START_ADDRESS)); + String endAddressString = prefs.getString(DisassemblyPreferenceConstants.END_ADDRESS); + if(endAddressString.startsWith("0x")) //$NON-NLS-1$ + fEndAddress = new BigInteger(endAddressString.substring(2), 16); + else + fEndAddress = new BigInteger(endAddressString, 16); + // TLETODO [disassembly[ source only mode + fSourceOnlyMode = false; //prefs.getBoolean(DisassemblyPreferenceConstants.USE_SOURCE_ONLY_MODE); + fShowSource = fSourceOnlyMode || prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_SOURCE); + fShowDisassembly = !fSourceOnlyMode || !fShowSource; + fShowOpcodes = prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_FUNCTION_OFFSETS); + fShowSymbols = prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_SYMBOLS); + fUpdateBeforeFocus = !prefs.getBoolean(DisassemblyPreferenceConstants.AVOID_READ_BEFORE_PC); + fPCHistorySizeMax = prefs.getInt(DisassemblyPreferenceConstants.PC_HISTORY_SIZE); + } + + public void logWarning(String message, Throwable error) { + DsfDebugUIPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, DsfDebugUIPlugin.PLUGIN_ID, message, error)); + } + + /* + * @see IAdaptable#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class required) { + if (IVerticalRulerInfo.class.equals(required)) { + if (fVerticalRuler != null) { + return fVerticalRuler; + } + } else if (IDisassemblyPart.class.equals(required)) { + return this; + } else if (IFindReplaceTarget.class.equals(required)) { + if (fFindReplaceTarget == null) { + fFindReplaceTarget = (fViewer == null ? null : fViewer.getFindReplaceTarget()); + } + return fFindReplaceTarget; + } else if (ITextOperationTarget.class.equals(required)) { + return (fViewer == null ? null : fViewer.getTextOperationTarget()); + } else if (Control.class.equals(required)) { + return fViewer != null ? fViewer.getTextWidget() : null; + } else if (IGotoMarker.class.equals(required)) { + return new IGotoMarker() { + public void gotoMarker(IMarker marker) { + DisassemblyPart.this.gotoMarker(marker); + }}; + } else if (IToggleBreakpointsTarget.class.equals(required)) { + return new IToggleBreakpointsTarget() { + public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { + ITextSelection textSelection = (ITextSelection)selection; + int line = textSelection.getStartLine(); + IBreakpoint[] bp = getBreakpointsAtLine(line); + if (bp == null || bp.length == 0) { + insertBreakpoint(line, false); + } else { + for (int i = 0; i < bp.length; i++) { + bp[i].delete(); + } + } + } + public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) { + return fDebugSessionId != null; + } + public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { + } + public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) { + return false; + } + public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException { + } + public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) { + return false; + }}; + } else if (IRunToLineTarget.class.equals(required)) { + return new IRunToLineTarget() { + public void runToLine(IWorkbenchPart part, ISelection selection, ISuspendResume target) throws CoreException { + ITextSelection textSelection = (ITextSelection)selection; + int line = textSelection.getStartLine(); + BigInteger address = getAddressOfLine(line); + // TLETODO [disassembly] run to line +// getRunControl().runUntil(...); + } + public boolean canRunToLine(IWorkbenchPart part, ISelection selection, ISuspendResume target) { + return fTargetContext != null && isSuspended(fTargetContext) ; + }}; + } + return super.getAdapter(required); + } + + private void setPreferenceStore(IPreferenceStore store) { + if (fPreferenceStore != null) { + fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener); + } + + fPreferenceStore = store; + + if (fPreferenceStore != null) { + fPreferenceStore.addPropertyChangeListener(fPropertyChangeListener); + } + } + + /** + * Handles a property change event describing a change of the editor's + * preference store and updates the preference related editor properties. + *

+ * Subclasses may extend. + *

+ * + * @param event + * the property change event + */ + protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { + + if (fViewer == null) + return; + + String property = event.getProperty(); + IPreferenceStore store = getPreferenceStore(); + + if (getFontPropertyPreferenceKey().equals(property)) { + initializeViewerFont(fViewer); + } else if (property.equals(DisassemblyPreferenceConstants.SHOW_ADDRESS_RULER)) { + fActionToggleAddressColumn.update(); + if (isAddressRulerVisible()) { + showAddressRuler(); + } else { + hideAddressRuler(); + } + } else if (property.equals(DisassemblyPreferenceConstants.ADDRESS_RADIX)) { + if (fAddressRulerColumn != null) { + hideAddressRuler(); + showAddressRuler(); + } + } else if (property.equals(DisassemblyPreferenceConstants.SHOW_ADDRESS_RADIX)) { + if (fAddressRulerColumn != null) { + hideAddressRuler(); + showAddressRuler(); + } + } else if (property.equals(DisassemblyPreferenceConstants.SHOW_SOURCE)) { + sourceModeChanged(store.getBoolean(property)); + } else if (property.equals(DisassemblyPreferenceConstants.INSTRUCTION_RADIX)) { + Runnable doit = new Runnable() { + public void run() { + fDocument.invalidateAddressRange(fStartAddress, fEndAddress, true); + if (!fShowDisassembly) { + fDocument.invalidateDisassemblyWithSource(true); + } + fDocument.setMaxOpcodeLength(0); + fGotoFramePending = true; + }}; + doScrollLocked(doit); + } else if (property.equals(DisassemblyPreferenceConstants.SHOW_SYMBOLS)) { + boolean showSymbols = store.getBoolean(property); + if (fShowSymbols == showSymbols) { + return; + } + fShowSymbols = showSymbols; + Runnable doit = new Runnable() { + public void run() { + fDocument.invalidateAddressRange(fStartAddress, fEndAddress, true); + if (!fShowDisassembly) { + fDocument.invalidateDisassemblyWithSource(true); + } + fGotoFramePending = true; + }}; + doScrollLocked(doit); + } else if (property.equals(DisassemblyPreferenceConstants.USE_SOURCE_ONLY_MODE)) { + fSourceOnlyMode = store.getBoolean(property); + if (fDebugSessionId != null) { + disassemblyModeChanged(isDissemblyMixedModeOn()); + } + } else if (property.equals(DisassemblyPreferenceConstants.SHOW_FUNCTION_OFFSETS)) { + fShowOpcodes = store.getBoolean(property); + fActionToggleFunctionColumn.update(); + if (isOpcodeRulerVisible()) { + showOpcodeRuler(); + } else { + hideOpcodeRuler(); + } + } else if (property.equals(DisassemblyPreferenceConstants.AVOID_READ_BEFORE_PC)) { + fUpdateBeforeFocus = !store.getBoolean(property); + updateVisibleArea(); + } else if (property.equals(fPCAnnotationColorKey)) { + fPCAnnotationRGB = PreferenceConverter.getColor(store, fPCAnnotationColorKey); + // redraw + for (Iterator it=fPCHistory.iterator(); it.hasNext();) { + AddressRangePosition pos = it.next(); + fViewer.invalidateTextPresentation(pos.offset, pos.length); + } + } else if (property.equals(DisassemblyPreferenceConstants.PC_HISTORY_SIZE)) { + fPCHistorySizeMax = store.getInt(property); + } + } + + /** + * This is a callback that will allow us to create the viewer and initialize + * it. + */ + @Override + public void createPartControl(Composite parent) { + fComposite = parent; + FillLayout layout = new FillLayout(); + layout.marginHeight = 2; + parent.setLayout(layout); + fVerticalRuler = createVerticalRuler(); + int styles = SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION; + fViewer = new DisassemblyViewer(parent, fVerticalRuler, getOverviewRuler(), true, styles); + SourceViewerConfiguration sourceViewerConfig = new DisassemblyViewerConfiguration(this); + fViewer.addTextPresentationListener(this); + fViewer.configure(sourceViewerConfig); + fDecorationSupport = new SourceViewerDecorationSupport(fViewer, getOverviewRuler(), getAnnotationAccess(), + getSharedColors()); + configureSourceViewerDecorationSupport(fDecorationSupport); + fDecorationSupport.install(getPreferenceStore()); + if (fPCAnnotationColorKey != null) { + fPCAnnotationRGB = PreferenceConverter.getColor(getPreferenceStore(), fPCAnnotationColorKey); + } else { + fPCAnnotationRGB = parent.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION).getRGB(); + } + + initializeViewerFont(fViewer); + createActions(); + hookRulerContextMenu(); + hookContextMenu(); + contributeToActionBars(); + + fViewer.addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateSelectionDependentActions(); + } + }); + + fDocument = createDocument(); + fViewer.setDocument(fDocument, new AnnotationModel()); + JFaceResources.getFontRegistry().addListener(fPropertyChangeListener); + + fErrorColor = getSharedColors().getColor(new RGB(96, 0, 0)); + fInstructionColor = getSharedColors().getColor(new RGB(0, 0, 96)); + fSourceColor = getSharedColors().getColor(new RGB(64, 0, 80)); + fLabelColor = getSharedColors().getColor(new RGB(0, 0, 96)); + + if (isAddressRulerVisible()) { + showAddressRuler(); + } + if (isOpcodeRulerVisible()) { + showOpcodeRuler(); + } + initDragAndDrop(); + PlatformUI.getWorkbench().getHelpSystem().setHelp(fViewer.getControl(), IDisassemblyHelpContextIds.DISASSEMBLY_VIEW); + updateTitle(); + updateStateDependentActions(); + + if (fDebugSessionId != null) { + debugContextChanged(); + } else { + updateDebugContext(); + } + } + + /* + * @see org.eclipse.ui.part.WorkbenchPart#setSite(org.eclipse.ui.IWorkbenchPartSite) + */ + @Override + protected void setSite(IWorkbenchPartSite site) { + super.setSite(site); + site.getPage().addPartListener(fPartListener); + } + + private DisassemblyDocument createDocument() { + DisassemblyDocument doc = new DisassemblyDocument(); + return doc; + } + + /* + * @see org.eclipse.ui.IWorkbenchPart#dispose() + */ + @Override + public void dispose() { + IWorkbenchPartSite site = getSite(); + site.setSelectionProvider(null); + site.getPage().removePartListener(fPartListener); + if (fHandlerActivations != null) { + IHandlerService handlerService = (IHandlerService)site.getService(IHandlerService.class); + handlerService.deactivateHandlers(fHandlerActivations); + fHandlerActivations = null; + } + if (fContextActivation != null) { + IContextService ctxService = (IContextService)site.getService(IContextService.class); + ctxService.deactivateContext(fContextActivation); + } + fViewer = null; + fDebugSessionId = null; + fTargetContext= null; + if (fServicesTracker != null) { + fServicesTracker.dispose(); + fServicesTracker= null; + } + fAnnotationAccess = null; + fAnnotationPreferences = null; + fAnnotationRulerColumn = null; + fComposite = null; + if (fDecorationSupport != null) { + fDecorationSupport.uninstall(); + fDecorationSupport = null; + } + if (fFont != null) { + fFont.dispose(); + fFont = null; + } + if (fDropTarget != null) { + fDropTarget.dispose(); + fDropTarget = null; + fDragSource.dispose(); + fDragSource = null; + } + if (fPropertyChangeListener != null) { + if (fPreferenceStore != null) { + fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener); + fPreferenceStore = null; + } + fPropertyChangeListener = null; + } + + fDocument.dispose(); + fDocument = null; + super.dispose(); + } + + private void initDragAndDrop() { + if (fDropTarget == null) { + Transfer[] dropTypes = new Transfer[] { FileTransfer.getInstance(), TextTransfer.getInstance() }; + Transfer[] dragTypes = new Transfer[] { TextTransfer.getInstance() }; + Control dropControl = getSourceViewer().getTextWidget(); + Control dragControl = dropControl; + int dropOps = DND.DROP_COPY | DND.DROP_DEFAULT; + int dragOps = DND.DROP_COPY | DND.DROP_DEFAULT; + + fDropTarget = new DropTarget(dropControl, dropOps); + fDropTarget.setTransfer(dropTypes); + fDropTargetAdapter = new DisassemblyDropAdapter(this); + fDropTarget.addDropListener(fDropTargetAdapter); + + fDragSource = new DragSource(dragControl, dragOps); + fDragSource.setTransfer(dragTypes); + fDragSourceAdapter = new TextViewerDragAdapter(getSourceViewer()); + fDragSource.addDragListener(fDragSourceAdapter); + } + } + + private ISourceViewer getSourceViewer() { + return fViewer; + } + + protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) { + Iterator e = fAnnotationPreferences.getAnnotationPreferences().iterator(); + while (e.hasNext()) { + AnnotationPreference pref = (AnnotationPreference)e.next(); + support.setAnnotationPreference(pref); + if (pref.getAnnotationType().equals(fPCAnnotation.getType())) { + fPCAnnotationColorKey = pref.getColorPreferenceKey(); + } + } + support.setCursorLinePainterPreferenceKeys(CURRENT_LINE, CURRENT_LINE_COLOR); + support.setSymbolicFontName(getFontPropertyPreferenceKey()); + } + + /** + * Returns the symbolic font name for this view as defined in XML. + * + * @return a String with the symbolic font name or null if + * none is defined + */ + private String getSymbolicFontName() { + if (getConfigurationElement() != null) + return getConfigurationElement().getAttribute("symbolicFontName"); //$NON-NLS-1$ + else + return null; + } + + protected final String getFontPropertyPreferenceKey() { + String symbolicFontName = getSymbolicFontName(); + + if (symbolicFontName != null) + return symbolicFontName; + else + return JFaceResources.TEXT_FONT; + } + + /** + * Initializes the given viewer's font. + * + * @param viewer + * the viewer + */ + private void initializeViewerFont(ISourceViewer viewer) { + + boolean isSharedFont = true; + Font font = null; + String symbolicFontName = getSymbolicFontName(); + + if (symbolicFontName != null) + font = JFaceResources.getFont(symbolicFontName); + else if (fPreferenceStore != null) { + // Backward compatibility + if (fPreferenceStore.contains(JFaceResources.TEXT_FONT) + && !fPreferenceStore.isDefault(JFaceResources.TEXT_FONT)) { + FontData data = PreferenceConverter.getFontData(fPreferenceStore, JFaceResources.TEXT_FONT); + + if (data != null) { + isSharedFont = false; + font = new Font(viewer.getTextWidget().getDisplay(), data); + } + } + } + if (font == null) + font = JFaceResources.getTextFont(); + + setFont(viewer, font); + + if (fFont != null) { + fFont.dispose(); + fFont = null; + } + + if (!isSharedFont) + fFont = font; + } + + /** + * Sets the font for the given viewer sustaining selection and scroll + * position. + * + * @param sourceViewer + * the source viewer + * @param font + * the font + */ + private void setFont(ISourceViewer sourceViewer, Font font) { + if (sourceViewer.getDocument() != null) { + + Point selection = sourceViewer.getSelectedRange(); + int topIndex = sourceViewer.getTopIndex(); + + StyledText styledText = sourceViewer.getTextWidget(); + Control parent = styledText; + if (sourceViewer instanceof ITextViewerExtension) { + ITextViewerExtension extension = (ITextViewerExtension) sourceViewer; + parent = extension.getControl(); + } + + parent.setRedraw(false); + + styledText.setFont(font); + + if (fVerticalRuler instanceof IVerticalRulerExtension) { + IVerticalRulerExtension e = (IVerticalRulerExtension) fVerticalRuler; + e.setFont(font); + } + + sourceViewer.setSelectedRange(selection.x, selection.y); + sourceViewer.setTopIndex(topIndex); + + if (parent instanceof Composite) { + Composite composite = (Composite) parent; + composite.layout(true); + } + + parent.setRedraw(true); + + } else { + + StyledText styledText = sourceViewer.getTextWidget(); + styledText.setFont(font); + + if (fVerticalRuler instanceof IVerticalRulerExtension) { + IVerticalRulerExtension e = (IVerticalRulerExtension) fVerticalRuler; + e.setFont(font); + } + } + } + + protected IVerticalRuler createVerticalRuler() { + CompositeRuler ruler = createCompositeRuler(); + IPreferenceStore store = getPreferenceStore(); + if (ruler != null && store != null) { + for (Iterator iter = ruler.getDecoratorIterator(); iter.hasNext();) { + IVerticalRulerColumn column = (IVerticalRulerColumn) iter.next(); + if (column instanceof AnnotationRulerColumn) { + fAnnotationRulerColumn = (AnnotationRulerColumn) column; + for (Iterator iter2 = fAnnotationPreferences.getAnnotationPreferences().iterator(); iter2.hasNext();) { + AnnotationPreference preference = (AnnotationPreference) iter2.next(); + String key = preference.getVerticalRulerPreferenceKey(); + boolean showAnnotation = true; + if (key != null && store.contains(key)) + showAnnotation = store.getBoolean(key); + if (showAnnotation) + fAnnotationRulerColumn.addAnnotationType(preference.getAnnotationType()); + } + fAnnotationRulerColumn.addAnnotationType(Annotation.TYPE_UNKNOWN); + break; + } + } + } + return ruler; + } + + /** + * Returns the vertical ruler. + * + * @return the vertical ruler + */ + protected IVerticalRuler getVerticalRuler() { + return fVerticalRuler; + } + + /** + * Returns the overview ruler. + * + * @return the overview ruler + */ + protected IOverviewRuler getOverviewRuler() { + if (fOverviewRuler == null) + fOverviewRuler = createOverviewRuler(getSharedColors()); + return fOverviewRuler; + } + + protected ISharedTextColors getSharedColors() { + return EditorsUI.getSharedTextColors(); + } + + protected IOverviewRuler createOverviewRuler(ISharedTextColors sharedColors) { + IOverviewRuler ruler = new OverviewRuler(getAnnotationAccess(), VERTICAL_RULER_WIDTH, sharedColors); + Iterator e = fAnnotationPreferences.getAnnotationPreferences().iterator(); + while (e.hasNext()) { + AnnotationPreference preference = (AnnotationPreference) e.next(); + if (preference.contributesToHeader()) + ruler.addHeaderAnnotationType(preference.getAnnotationType()); + } + return ruler; + } + + /** + * Creates a new address ruler column that is appropriately initialized. + * + * @return the created line number column + */ + protected IVerticalRulerColumn createAddressRulerColumn() { + fAddressRulerColumn= new AddressRulerColumn(); + initializeRulerColumn(fAddressRulerColumn, DisassemblyPreferenceConstants.ADDRESS_COLOR); + IPreferenceStore prefs = getPreferenceStore(); + fAddressRulerColumn.setRadix(prefs.getInt(DisassemblyPreferenceConstants.ADDRESS_RADIX)); + fAddressRulerColumn.setShowRadixPrefix(prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_ADDRESS_RADIX)); + return fAddressRulerColumn; + } + + /** + * Creates a new ruler column that is appropriately initialized. + * + * @return the created line number column + */ + protected IVerticalRulerColumn createOpcodeRulerColumn() { + fOpcodeRulerColumn= new FunctionOffsetRulerColumn(); + initializeRulerColumn(fOpcodeRulerColumn, DisassemblyPreferenceConstants.OPCODE_COLOR); + return fOpcodeRulerColumn; + } + + /** + * Initializes the given address ruler column from the preference store. + * + * @param rulerColumn the ruler column to be initialized + */ + protected void initializeRulerColumn(DisassemblyRulerColumn rulerColumn, String colorPrefKey) { + ISharedTextColors sharedColors= getSharedColors(); + IPreferenceStore store= getPreferenceStore(); + if (store != null) { + + RGB rgb= null; + // foreground color + if (store.contains(colorPrefKey)) { + if (store.isDefault(colorPrefKey)) + rgb= PreferenceConverter.getDefaultColor(store, colorPrefKey); + else + rgb= PreferenceConverter.getColor(store, colorPrefKey); + } + if (rgb == null) + rgb= new RGB(0, 0, 0); + rulerColumn.setForeground(sharedColors.getColor(rgb)); + + rgb= null; + + rulerColumn.redraw(); + } + } + + + /** + * @return the preference store + */ + private IPreferenceStore getPreferenceStore() { + return fPreferenceStore; + } + + /** + * Creates a composite ruler to be used as the vertical ruler by this + * editor. Subclasses may re-implement this method. + * + * @return the vertical ruler + */ + protected CompositeRuler createCompositeRuler() { + CompositeRuler ruler = new CompositeRuler(); + ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH, getAnnotationAccess())); + return ruler; + } + + private boolean isAddressRulerVisible() { + return getPreferenceStore().getBoolean(DisassemblyPreferenceConstants.SHOW_ADDRESS_RULER); + } + + /** + * Shows the address ruler column. + */ + private void showAddressRuler() { + if (fAddressRulerColumn == null) { + IVerticalRuler v= getVerticalRuler(); + if (v instanceof CompositeRuler) { + CompositeRuler c= (CompositeRuler) v; + c.addDecorator(1, createAddressRulerColumn()); + } + } + } + + /** + * Hides the address ruler column. + */ + private void hideAddressRuler() { + if (fAddressRulerColumn != null) { + IVerticalRuler v= getVerticalRuler(); + if (v instanceof CompositeRuler) { + CompositeRuler c= (CompositeRuler) v; + c.removeDecorator(fAddressRulerColumn); + } + fAddressRulerColumn = null; + } + } + + private boolean isOpcodeRulerVisible() { + return fShowOpcodes; + } + + /** + * Shows the opcode ruler column. + */ + private void showOpcodeRuler() { + if (fOpcodeRulerColumn == null) { + IVerticalRuler v= getVerticalRuler(); + if (v instanceof CompositeRuler) { + CompositeRuler c= (CompositeRuler) v; + c.addDecorator(2, createOpcodeRulerColumn()); + } + } + } + + /** + * Hides the opcode ruler column. + */ + private void hideOpcodeRuler() { + if (fOpcodeRulerColumn != null) { + IVerticalRuler v= getVerticalRuler(); + if (v instanceof CompositeRuler) { + CompositeRuler c= (CompositeRuler) v; + c.removeDecorator(fOpcodeRulerColumn); + } + fOpcodeRulerColumn = null; + } + } + + /** + * Returns the annotation access. + * + * @return the annotation access + */ + protected IAnnotationAccess getAnnotationAccess() { + if (fAnnotationAccess == null) + fAnnotationAccess = createAnnotationAccess(); + return fAnnotationAccess; + } + + /** + * Creates the annotation access for this editor. + * + * @return the created annotation access + */ + protected IAnnotationAccess createAnnotationAccess() { + return new DefaultMarkerAnnotationAccess(); + } + + private void hookContextMenu() { + String id = "#DisassemblyPartContext"; //$NON-NLS-1$ + MenuManager menuMgr = new MenuManager(id, id); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + DisassemblyPart.this.fillContextMenu(manager); + } + }); + Menu menu = menuMgr.createContextMenu(fViewer.getTextWidget()); + fViewer.getTextWidget().setMenu(menu); + getSite().registerContextMenu(id, menuMgr, fViewer); + } + + private void hookRulerContextMenu() { + String id = "#DisassemblyPartRulerContext"; //$NON-NLS-1$ + MenuManager menuMgr = new MenuManager(id, id); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + DisassemblyPart.this.fillRulerContextMenu(manager); + } + }); + Menu menu = menuMgr.createContextMenu(fVerticalRuler.getControl()); + fVerticalRuler.getControl().setMenu(menu); + getSite().registerContextMenu(id, menuMgr, fViewer); + } + + private void contributeToActionBars() { + IWorkbenchPartSite site = getSite(); + site.setSelectionProvider(fViewer); + IContextService ctxService = (IContextService)site.getService(IContextService.class); + fContextActivation = ctxService.activateContext(KEY_BINDING_CONTEXT_DISASSEMBLY); + contributeToActionBars(getActionBars()); + } + + protected abstract IActionBars getActionBars(); + + protected void contributeToActionBars(IActionBars bars) { + for (Iterator iter = fGlobalActions.keySet().iterator(); iter.hasNext();) { + String key = iter.next(); + IAction action = fGlobalActions.get(key); + bars.setGlobalActionHandler(key, action); + } + IMenuManager menu = bars.getMenuManager(); + IMenuManager navigateMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE); + if (navigateMenu != null) { + navigateMenu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, fActionGotoPC); + navigateMenu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, fActionGotoAddress); + navigateMenu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, fActionGotoSymbol); + } + bars.updateActionBars(); + } + + protected void fillContextMenu(IMenuManager manager) { + Point cursorLoc = getSite().getShell().getDisplay().getCursorLocation(); + fContextClickLocation = fViewer.getTextWidget().toControl(cursorLoc); + fActionToggleSource.update(); + fActionToggleSymbols.update(); + manager.add(new GroupMarker("group.top")); // ICommonMenuConstants.GROUP_TOP //$NON-NLS-1$ + manager.add(new Separator("group.breakpoints")); //$NON-NLS-1$ + manager.add(new Separator(IWorkbenchActionConstants.GO_TO)); + manager.add(fActionGotoPC); + manager.add(fActionGotoAddress); + manager.add(fActionGotoSymbol); + manager.add(new Separator("group.debug")); //$NON-NLS-1$ + manager.add(new Separator(ITextEditorActionConstants.GROUP_EDIT)); + manager.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, fGlobalActions.get(ITextEditorActionConstants.COPY)); + manager.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, fGlobalActions.get(ITextEditorActionConstants.SELECT_ALL)); + manager.add(new Separator(ITextEditorActionConstants.GROUP_SETTINGS)); + manager.add(fActionToggleSource); + manager.add(fActionToggleSymbols); + manager.add(fActionOpenPreferences); + manager.add(new Separator()); + manager.add(fActionRefreshView); + // Other plug-ins can contribute their actions here + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + protected void fillRulerContextMenu(IMenuManager manager) { + fActionToggleBreakpoint.update(); + fActionToggleBreakpointEnablement.update(); + fActionToggleAddressColumn.update(); + fActionToggleFunctionColumn.update(); + + manager.add(new GroupMarker("group.top")); // ICommonMenuConstants.GROUP_TOP //$NON-NLS-1$ + manager.add(new Separator("group.breakpoints")); //$NON-NLS-1$ + manager.add(fActionToggleBreakpoint); + manager.add(fActionToggleBreakpointEnablement); + manager.add(new GroupMarker("debug")); //$NON-NLS-1$ + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + manager.add(new GroupMarker(ITextEditorActionConstants.GROUP_RESTORE)); + manager.add(new Separator("add")); //$NON-NLS-1$ + manager.add(new Separator(ITextEditorActionConstants.GROUP_RULERS)); + manager.add(fActionToggleAddressColumn); + manager.add(fActionToggleFunctionColumn); + manager.add(new Separator(ITextEditorActionConstants.GROUP_REST)); + + for (Object listener : fRulerContextMenuListeners.getListeners()) + ((IMenuListener) listener).menuAboutToShow(manager); + + manager.add(new Separator(ITextEditorActionConstants.GROUP_EDIT)); + manager.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, fGlobalActions.get(ITextEditorActionConstants.COPY)); + } + + protected void fillLocalToolBar(IToolBarManager manager) { + manager.add(fActionGotoPC); + manager.add(fActionGotoAddress); + } + + protected void updateSelectionDependentActions() { + Iterator iterator= fSelectionActions.iterator(); + while (iterator.hasNext()) { + IUpdate action = (IUpdate)iterator.next(); + action.update(); + } + } + + protected void updateStateDependentActions() { + Iterator iterator= fStateDependentActions.iterator(); + while (iterator.hasNext()) { + IUpdate action = iterator.next(); + action.update(); + } + } + + protected void createActions() { + Action action; + action= new TextOperationAction(fViewer, ITextOperationTarget.COPY); + action.setText(DisassemblyMessages.Disassembly_action_Copy_label); + action.setImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Copy_enabled)); + action.setDisabledImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Copy_disabled)); + action.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY); + fGlobalActions.put(ITextEditorActionConstants.COPY, action); + fSelectionActions.add(action); + + action= new TextOperationAction(fViewer, ITextOperationTarget.SELECT_ALL); + action.setText(DisassemblyMessages.Disassembly_action_SelectAll_label); + action.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL); + fGlobalActions.put(ITextEditorActionConstants.SELECT_ALL, action); + + action= new TextOperationAction(fViewer, ITextOperationTarget.PRINT); + action.setActionDefinitionId(IWorkbenchActionDefinitionIds.PRINT); + fGlobalActions.put(ITextEditorActionConstants.PRINT, action); + + fActionGotoPC = new ActionGotoProgramCounter(this); + fActionGotoPC.setActionDefinitionId(COMMAND_ID_GOTO_PC); + fStateDependentActions.add(fActionGotoPC); + registerWithHandlerService(fActionGotoPC); + + fActionGotoAddress = new ActionGotoAddress(this); + fActionGotoAddress.setActionDefinitionId(COMMAND_ID_GOTO_ADDRESS); + fStateDependentActions.add(fActionGotoAddress); + registerWithHandlerService(fActionGotoAddress); + + fActionGotoSymbol = new ActionGotoSymbol(this); + fActionGotoSymbol.setActionDefinitionId(COMMAND_ID_GOTO_SYMBOL); + fStateDependentActions.add(fActionGotoSymbol); + registerWithHandlerService(fActionGotoSymbol); + + fActionToggleSource = new ActionToggleSource(); + fStateDependentActions.add(fActionToggleSource); + fActionToggleBreakpoint = new ActionToggleBreakpoint(); +// fActionToggleBreakpoint.setActionDefinitionId(COMMAND_ID_TOGGLE_BREAKPOINT); +// registerWithHandlerService(fActionToggleBreakpoint); + fVerticalRuler.getControl().addMouseListener(new MouseAdapter() { + @Override + public void mouseDoubleClick(MouseEvent e) { + fActionToggleBreakpoint.update(); + if (fActionToggleBreakpoint.isEnabled()) { + fActionToggleBreakpoint.run(); + } + } + }); + fActionToggleBreakpointEnablement = new ActionToggleBreakpointEnablement(); + fActionToggleAddressColumn = new ActionToggleAddressColumn(); + fActionToggleFunctionColumn = new ActionToggleFunctionColumn(); + fActionToggleSymbols = new ActionToggleSymbols(); +// fActionSourceSteppingMode.setActionDefinitionId(COMMAND_ID_TOGGLE_STEPPING_MODE); +// registerWithHandlerService(fActionSourceSteppingMode); + fActionRefreshView = new ActionRefreshView(); + fStateDependentActions.add(fActionRefreshView); + fGlobalActions.put(ActionFactory.REFRESH.getId(), fActionRefreshView); + fActionOpenPreferences = new ActionOpenPreferences(getSite().getShell()); + } + + /** + * Register given action with the handler service for key bindings. + * + * @param action + */ + private void registerWithHandlerService(IAction action) { + if (fHandlerActivations == null) { + fHandlerActivations = new ArrayList(5); + } + IHandlerService handlerService = (IHandlerService)getSite().getService(IHandlerService.class); + fHandlerActivations.add(handlerService.activateHandler(action.getActionDefinitionId(), new ActionHandler(action))); + } + + private void gotoFrame(IFrameDMContext frame) { + if (fActive) { + gotoFrame(frame.getLevel(), PC_UNKNOWN); + } + } + + private void gotoFrame(int frame) { + if (fActive) { + gotoFrame(frame, PC_UNKNOWN); + } + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#gotoProgramCounter() + */ + public final void gotoProgramCounter() { + if (fPCAddress != PC_RUNNING) { + updatePC(fPCAddress); + } + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#gotoAddress(java.math.BigInteger) + */ + public final void gotoAddress(BigInteger address) { + fFocusAddress = address; + if (fDebugSessionId == null) { + return; + } + if (DEBUG) System.out.println("gotoAddress " + getAddressText(address)); //$NON-NLS-1$ + if (fGotoAddressPending == PC_UNKNOWN) { + fGotoAddressPending = address; + } + if (fUpdatePending) { + return; + } + AddressRangePosition pos = getPositionOfAddress(address); + if (pos != null) { + if (pos.fValid) { + AddressRangePosition previousPos = /* fUpdateBeforeFocus ? getPositionOfAddress(pos.fAddressOffset-1): */ null; + if (previousPos == null || previousPos.fValid) { + if (fGotoAddressPending.equals(address)) { + fGotoAddressPending = PC_UNKNOWN; + } + gotoPosition(pos, false); + } else { + int lines = fBufferZone+3; + BigInteger endAddress = pos.fAddressOffset; + BigInteger startAddress = previousPos.fAddressOffset.max( + endAddress.subtract(BigInteger.valueOf(lines * fDocument.getMeanSizeOfInstructions()))); + retrieveDisassembly(startAddress, endAddress, lines); + } + } else { + int lines = fBufferZone+3; + BigInteger endAddress = pos.fAddressOffset.add(pos.fAddressLength).min( + address.add(BigInteger.valueOf(lines * fDocument.getMeanSizeOfInstructions()))); + retrieveDisassembly(address, endAddress, lines); + } + } + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#gotoSymbol(java.lang.String) + */ + public final void gotoSymbol(final String symbol) { + if (!fActive || !isSuspended() || fTargetFrameContext == null) { + return; + } + final IExpressions expressions= getService(IExpressions.class); + if (expressions == null) { + return; + } + IExpressionDMContext exprDmc= expressions.createExpression(fTargetContext, '&'+symbol); + final FormattedValueDMContext valueDmc= expressions.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT); + final DsfExecutor executor= getSession().getExecutor(); + executor.submit(new Runnable() { + public void run() { + expressions.getFormattedExpressionValue(valueDmc, new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + FormattedValueDMData data= getData(); + final String value= data.getFormattedValue(); + final BigInteger address= decodeAddress(value); + if (address != null) { + asyncExec(new Runnable() { + public void run() { + gotoAddress(address); + }}); + } + } + @Override + protected void handleError() { + asyncExec(new Runnable() { + public void run() { + ErrorDialog.openError(getSite().getShell(), "Error", null, getStatus()); //$NON-NLS-1$ + }}); + } + }); + }}); + } + + private void gotoPosition(Position pos, boolean select) { + if (fViewer == null) { + return; + } + setFocusPosition(pos); + fViewer.setSelectedRange(pos.offset, select ? Math.max(pos.length-1, 0) : 0); + int revealOffset = pos.offset; + boolean onTop = false; + if (/* !fUpdateBeforeFocus && */ pos.offset > 0) { + try { + AddressRangePosition previousPos = fDocument.getModelPosition(pos.offset - 1); + if (previousPos instanceof LabelPosition) { + revealOffset = previousPos.offset; + onTop = true; + } else if (!previousPos.fValid) { + onTop = true; + } + } catch (BadLocationException e) { + // cannot happen + } + } + fViewer.revealOffset(revealOffset, onTop); + } + + private void gotoMarker(final IMarker marker) { + if (marker == null) { + return; + } + if (fDebugSessionId == null || fUpdatePending) { + fGotoMarkerPending = marker; + return; + } + fGotoMarkerPending = null; + + //TLETODO [disassembly] goto (breakpoint) marker + } + + /* + * @see org.eclipse.jface.text.IViewportListener#viewportChanged(int) + */ + public void viewportChanged(int verticalOffset) { + if (fDebugSessionId != null && fGotoAddressPending == PC_UNKNOWN && fScrollPos == null && !fUpdatePending && !fRefreshViewPending) { + fUpdatePending = true; + invokeLater(new Runnable() { + public void run() { + assert fUpdatePending; + if (fUpdatePending) { + fUpdatePending = false; + updateVisibleArea(); + } + } + }); + } + } + + /** + * Update lines of currently visible area + one page buffer zone below. + */ + private void updateVisibleArea() { + if (!fActive || fUpdatePending || fViewer == null || fDebugSessionId == null) { + return; + } + if (fTargetContext == null || !isSuspended(fTargetContext) || fFrameAddress == PC_UNKNOWN) { + return; + } + StyledText styledText = fViewer.getTextWidget(); + Rectangle clientArea = styledText.getClientArea(); + fBufferZone = Math.max(8, clientArea.height / styledText.getLineHeight()); + int topIndex = fViewer.getTopIndex(); + int bottomIndex = fViewer.getBottomIndex(); + int focusIndex = -1; + boolean focusVisible = false; + boolean isScrollingUp = fViewer.isUserTriggeredScrolling() && fViewer.getLastTopPixel() >= styledText.getTopPixel(); + if (fFocusPos != null) { + try { + int focusOffset = fFocusPos.offset; + focusIndex = fDocument.getLineOfOffset(focusOffset); + focusVisible = focusIndex >= topIndex && focusIndex <= bottomIndex; + // workaround for: Clicking the IP annotation in the right ruler has no effect. + // we deselect the IP location if it is scrolled outside the visible area + if (!focusVisible) { + Point selection = fViewer.getSelectedRange(); + if (selection.x == focusOffset && selection.y > 0) { + fViewer.setSelectedRange(selection.x, 0); + } + } + } catch (BadLocationException e) { + setFocusPosition(null); + } + } + if (!focusVisible) { + focusIndex = topIndex + fScrollLine; + } + BigInteger focusAddress = getAddressOfLine(focusIndex); + bottomIndex += 2; + AddressRangePosition bestPosition = null; + int bestLine = -1; + BigInteger bestDistance = null; + Iterator it = fDocument.getInvalidAddressRanges().iterator(); + while (it.hasNext()) { + AddressRangePosition p = it.next(); + try { + int line = fDocument.getLineOfOffset(p.offset); + if (line >= topIndex && line <= bottomIndex) { + if (p instanceof DisassemblyPosition || p.fAddressLength.compareTo( + BigInteger.valueOf(fBufferZone * 2)) <= 0) { + // small areas and known areas are OK to update + } else if (!isScrollingUp && !fUpdateBeforeFocus + && p.fAddressOffset.compareTo(focusAddress) < 0) { + continue; + } + BigInteger distance = p.fAddressOffset.subtract(focusAddress).abs(); + if (bestDistance == null || distance.compareTo(bestDistance) < 0) { + bestPosition = p; + bestLine = line; + bestDistance = distance; + if (bestDistance.compareTo(BigInteger.valueOf(fBufferZone * 2)) <= 0) { + break; + } + } + } + } catch (BadLocationException e) { + continue; + } + } + if (bestPosition != null) { + int lines = fBufferZone+3; + BigInteger startAddress = bestPosition.fAddressOffset; + BigInteger endAddress = bestPosition.fAddressOffset.add(bestPosition.fAddressLength); + BigInteger addressRange = BigInteger.valueOf(lines * fDocument.getMeanSizeOfInstructions()); + if (bestLine > focusIndex || bestLine == focusIndex && startAddress.compareTo(focusAddress) >= 0) { + // insert at start of range + if (endAddress.subtract(startAddress).compareTo(addressRange) < 0) { + // try to increase range to reduce number of requests + Iterator iter = fDocument.getModelPositionIterator(endAddress); + while (iter.hasNext()) { + AddressRangePosition p = (AddressRangePosition)iter.next(); + if (p.fValid) { + endAddress = endAddress.add(p.fAddressLength); + if (endAddress.subtract(startAddress).compareTo(addressRange) >= 0) { + break; + } + } else { + break; + } + } + } + } else { + // insert at end of range + startAddress = startAddress.max(endAddress.subtract(addressRange)); + // make sure we get all disassembly lines until endAddress + lines = endAddress.subtract(startAddress).intValue(); + } + retrieveDisassembly(startAddress, endAddress, lines); + } + scheduleDoPending(); + } + + private void asyncExec(Runnable runnable) { + if (fViewer != null) { + fViewer.getControl().getDisplay().asyncExec(runnable); + } + } + private void invokeLater(Runnable runnable) { + invokeLater(10, runnable); + } + private void invokeLater(int delay, Runnable runnable) { + if (fViewer != null) { + fViewer.getControl().getDisplay().timerExec(delay, runnable); + } + } + + /** + * Insert sourcelines if available. + */ + /*default*/ void updateInvalidSource() { + if (fViewer == null) { + return; + } + boolean unlock = false; + try { + if (fScrollPos == null) { + if (fUpdatePending) { + fUpdateSourcePending= true; + return; + } + fUpdateSourcePending= false; + unlock = true; + fUpdatePending = true; + lockScroller(); + } + ArrayList copy = new ArrayList(fDocument.getInvalidSource()); + Iterator it = copy.iterator(); + while (it.hasNext()) { + SourcePosition p = it.next(); + if (!p.fValid) { + insertSource(p); + } else if (DEBUG && fDocument.getInvalidSource().remove(p)) { + System.err.println("!!! valid source position in invalid source list at "+getAddressText(p.fAddressOffset)); //$NON-NLS-1$ + } + } + } finally { + if (unlock) { + fUpdatePending = false; + unlockScroller(); + doPending(); + } + } + } + + /** + * Show disassembly for given (source) file. + * + * @param file + * @param lines + */ + void retrieveDisassembly(final String file, final int lines, final boolean mixed) { + if (fDebugSessionId == null) { + return; + } + if (fUpdatePending) { + invokeLater(new Runnable() { + public void run() { + retrieveDisassembly(file, lines, mixed); + }}); + return; + } + if (DEBUG) System.out.println("retrieveDisassembly "+file); //$NON-NLS-1$ + String debuggerPath= file; + + // try reverse lookup + final ISourceLookup lookup= getService(ISourceLookup.class); + final ISourceLookupDMContext ctx= DMContexts.getAncestorOfType(fTargetContext, ISourceLookupDMContext.class); + final DsfExecutor executor= getSession().getExecutor(); + Query query= new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + final DataRequestMonitor request= new DataRequestMonitor(executor, rm) { + @Override + protected void handleSuccess() { + rm.setData(getData()); + rm.done(); + } + }; + lookup.getDebuggerPath(ctx, file, request); + } + }; + try { + getSession().getExecutor().execute(query); + debuggerPath= query.get(); + } catch (InterruptedException exc) { + internalError(exc); + } catch (ExecutionException exc) { + internalError(exc); + } + + final IDisassembly disassembly= fServicesTracker.getService(IDisassembly.class); + final IDisassemblyDMContext context= DMContexts.getAncestorOfType(fTargetContext, IDisassemblyDMContext.class); + + final String finalFile= debuggerPath; + final DataRequestMonitor disassemblyRequest= new DataRequestMonitor(executor, null) { + @Override + public void handleCompleted() { + final IMixedInstruction[] data= getData(); + if (!isCanceled() && data != null) { + asyncExec(new Runnable() { + public void run() { + if (!insertDisassembly(null, data)) { + // retry in non-mixed mode + retrieveDisassembly(file, lines, false); + } + }}); + } else { + final IStatus status= getStatus(); + if (status != null && !status.isOK()) { + asyncExec(new Runnable() { + public void run() { + ErrorDialog.openError(getSite().getShell(), "Error", null, getStatus()); //$NON-NLS-1$ + } + }); + } + fUpdatePending= false; + } + } + }; + assert !fUpdatePending; + fUpdatePending = true; + executor.submit(new Runnable() { + public void run() { + disassembly.getMixedInstructions(context, finalFile, 1, lines, disassemblyRequest); + }}); + } + + private void retrieveDisassembly(BigInteger startAddress, BigInteger endAddress, int lines) { + if (fDebugSessionId == null) { + return; + } + if (DEBUG) System.out.println("retrieveDisassembly "+getAddressText(startAddress)+" "+lines+" lines"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + retrieveDisassembly(startAddress, endAddress, lines, true); + } + + private void retrieveDisassembly(final BigInteger startAddress, BigInteger endAddress, final int linesHint, boolean mixed) { + assert !fUpdatePending; + fUpdatePending = true; + final int lines= linesHint + 2; + final BigInteger addressLength= BigInteger.valueOf(lines * 4); + if (endAddress.subtract(startAddress).compareTo(addressLength) > 0) { + endAddress= startAddress.add(addressLength); + } + boolean insideActiveFrame= startAddress.equals(fFrameAddress); + String file= null; + int lineNumber= -1; + if (insideActiveFrame && fTargetFrameData != null) { + file= fTargetFrameData.getFile(); + if (file != null && file.trim().length() == 0) { + file= null; + } + lineNumber= fTargetFrameData.getLine(); + } + final String finalFile= file; + final int finalLineNumber= lineNumber; + final BigInteger finalEndAddress= endAddress; + + final DsfExecutor executor= getSession().getExecutor(); + final IDisassembly disassembly= fServicesTracker.getService(IDisassembly.class); + final IDisassemblyDMContext context= DMContexts.getAncestorOfType(fTargetContext, IDisassemblyDMContext.class); + + if (mixed) { + final DataRequestMonitor disassemblyRequest= new DataRequestMonitor(executor, null) { + @Override + public void handleCompleted() { + final IMixedInstruction[] data= getData(); + if (!isCanceled() && data != null) { + asyncExec(new Runnable() { + public void run() { + if (!insertDisassembly(startAddress, data)) { + // retry in non-mixed mode + retrieveDisassembly(startAddress, finalEndAddress, linesHint, false); + } + }}); + } else { + final IStatus status= getStatus(); + if (status != null && !status.isOK()) { + asyncExec(new Runnable() { + public void run() { + doScrollLocked(new Runnable() { + public void run() { + insertError(startAddress, status.getMessage()); + } + }); + }}); + } + fUpdatePending= false; + } + } + }; + if (file != null) { + executor.submit(new Runnable() { + public void run() { + disassembly.getMixedInstructions(context, finalFile, finalLineNumber, lines*2, disassemblyRequest); + }}); + } else { + executor.submit(new Runnable() { + public void run() { + disassembly.getMixedInstructions(context, startAddress, finalEndAddress, disassemblyRequest); + }}); + } + } else { + final DataRequestMonitor disassemblyRequest= new DataRequestMonitor(executor, null) { + @Override + public void handleCompleted() { + if (!isCanceled() && getData() != null) { + asyncExec(new Runnable() { + public void run() { + insertDisassembly(startAddress, getData()); + }}); + } else { + final IStatus status= getStatus(); + if (status != null && !status.isOK()) { + asyncExec(new Runnable() { + public void run() { + doScrollLocked(new Runnable() { + public void run() { + insertError(startAddress, status.getMessage()); + } + }); + }}); + } + fUpdatePending= false; + } + } + }; + if (file != null) { + executor.submit(new Runnable() { + public void run() { + disassembly.getInstructions(context, finalFile, finalLineNumber, lines, disassemblyRequest); + }}); + } else { + executor.submit(new Runnable() { + public void run() { + disassembly.getInstructions(context, startAddress, finalEndAddress, disassemblyRequest); + }}); + } + } + } + + private void insertError(BigInteger address, String message) { + AddressRangePosition p = null; + p = getPositionOfAddress(address); + if (p.fValid) { + return; + } + try { + fDocument.insertErrorLine(p, address, BigInteger.ONE, message); + } catch (BadLocationException exc) { + internalError(exc); + } + } + + private void insertDisassembly(BigInteger startAddress, IInstruction[] instructions) { + if (fViewer == null || fDebugSessionId == null) { + return; + } + if (DEBUG) System.out.println("insertDisassembly "+getAddressText(startAddress)); //$NON-NLS-1$ + assert fUpdatePending; + if (!fUpdatePending) { + // safe-guard in case something weird is going on + return; + } + try { + lockScroller(); + + AddressRangePosition p= null; + for (int j = 0; j < instructions.length; j++) { + IInstruction instruction = instructions[j]; + BigInteger address= instruction.getAdress(); + if (startAddress == null || startAddress.compareTo(BigInteger.ZERO) < 0) { + fGotoAddressPending = startAddress = address; + } + if (p == null || !p.containsAddress(address)) { + p = getPositionOfAddress(address); + } + if (p instanceof ErrorPosition && p.fValid) { + p.fValid = false; + fDocument.getInvalidAddressRanges().add(p); + } else if (p == null || p.fValid) { + if (DEBUG) System.out.println("Excess disassembly lines at " + getAddressText(address)); //$NON-NLS-1$ + return; + } + boolean hasSource= false; + String compilationPath= null; + // insert symbol label + final String functionName= instruction.getFuntionName(); + if (functionName != null && functionName.length() > 0 && instruction.getOffset() == 0) { + p = fDocument.insertLabel(p, address, functionName, fShowSymbols && (!hasSource || fShowDisassembly)); + } + // determine instruction byte length + BigInteger instrLength= null; + if (j < instructions.length - 1) { + instrLength= instructions[j+1].getAdress().subtract(instruction.getAdress()).abs(); + } else if (instructions.length == 1) { + if (p.fAddressLength.compareTo(BigInteger.valueOf(8)) <= 0) { + instrLength= p.fAddressLength; + } + } + if (instrLength == null) { + // cannot determine length of last instruction + break; + } + final String opCode; + // insert function name+offset instead of opcode bytes + if (functionName != null && functionName.length() > 0) { + opCode= functionName + '+' + instruction.getOffset(); + } else { + opCode= ""; //$NON-NLS-1$ + } + p = fDocument.insertDisassemblyLine(p, address, instrLength.intValue(), opCode, instruction.getInstruction(), compilationPath, -1); + if (p == null) { + break; + } + } + + } catch (BadLocationException e) { + // should not happen + internalError(e); + } finally { + fUpdatePending = false; + updateInvalidSource(); + unlockScroller(); + doPending(); + updateVisibleArea(); + } + } + + private boolean insertDisassembly(BigInteger startAddress, IMixedInstruction[] mixedInstructions) { + if (fViewer == null || fDebugSessionId == null) { + return true; + } + if (DEBUG) System.out.println("insertDisassembly "+getAddressText(startAddress)); //$NON-NLS-1$ + assert fUpdatePending; + if (!fUpdatePending) { + // safe-guard in case something weird is going on + return true; + } + // indicates whether disassembly for the start address was inserted + boolean success= false; + try { + lockScroller(); + + AddressRangePosition p= null; + for (int i = 0; i < mixedInstructions.length; ++i) { + IMixedInstruction mixedInstruction= mixedInstructions[i]; + final String file= mixedInstruction.getFileName(); + final int lineNumber= mixedInstruction.getLineNumber() - 1; + IInstruction[] instructions= mixedInstruction.getInstructions(); + for (int j = 0; j < instructions.length; ++j) { + IInstruction instruction = instructions[j]; + BigInteger address= instruction.getAdress(); + if (startAddress == null || startAddress.compareTo(BigInteger.ZERO) < 0) { + fGotoAddressPending = startAddress = address; + } + if (p == null || !p.containsAddress(address)) { + p = getPositionOfAddress(address); + } + if (p instanceof ErrorPosition && p.fValid) { + p.fValid = false; + fDocument.getInvalidAddressRanges().add(p); + } else if (p == null) { + if (DEBUG) System.out.println("Excess disassembly lines at " + getAddressText(address)); //$NON-NLS-1$ + return success; + } else if (p.fValid) { + if (DEBUG) System.out.println("Excess disassembly lines at " + getAddressText(address)); //$NON-NLS-1$ + if (file != null && lineNumber >= 0 || p.fAddressLength == BigInteger.ONE) { + // override probably unaligned disassembly + p.fValid = false; + fDocument.getInvalidAddressRanges().add(p); + } else { + return success; + } + } + boolean hasSource= false; + if (file != null && lineNumber >= 0) { + p = insertSource(p, address, file, lineNumber); + hasSource = fFile2Storage.get(file) != null; + } + // insert symbol label + final String functionName= instruction.getFuntionName(); + if (functionName != null && functionName.length() > 0 && instruction.getOffset() == 0) { + p = fDocument.insertLabel(p, address, functionName, fShowSymbols && (!hasSource || fShowDisassembly)); + } + // determine instruction byte length + BigInteger instrLength= null; + if (j < instructions.length - 1) { + instrLength= instructions[j+1].getAdress().subtract(instruction.getAdress()).abs(); + } else if (i < mixedInstructions.length - 1) { + int nextSrcLineIdx= i+1; + while (nextSrcLineIdx < mixedInstructions.length) { + IInstruction[] nextInstrs= mixedInstructions[nextSrcLineIdx].getInstructions(); + if (nextInstrs.length > 0) { + instrLength= nextInstrs[0].getAdress().subtract(instruction.getAdress()).abs(); + break; + } + ++nextSrcLineIdx; + } + if (nextSrcLineIdx >= mixedInstructions.length) { + break; + } + } else if (instructions.length == 1) { + if (p.fAddressLength.compareTo(BigInteger.valueOf(8)) <= 0) { + instrLength= p.fAddressLength; + } + } + if (instrLength == null) { + // cannot determine length of last instruction + break; + } + final String opCode; + // insert function name+offset instead of opcode bytes + if (functionName != null && functionName.length() > 0) { + opCode= functionName + '+' + instruction.getOffset(); + } else { + opCode= ""; //$NON-NLS-1$ + } + success= success || address.compareTo(startAddress) == 0; + p = fDocument.insertDisassemblyLine(p, address, instrLength.intValue(), opCode, instruction.getInstruction(), file, lineNumber); + if (p == null && success) { + break; + } + } + } + + } catch (BadLocationException e) { + // should not happen + internalError(e); + } finally { + fUpdatePending = false; + if (success) { + updateInvalidSource(); + unlockScroller(); + doPending(); + updateVisibleArea(); + } else { + unlockScroller(); + } + } + return success; + } + + private void retrieveFrameAddress(final IExecutionDMContext targetContext, final int frame) { + if (targetContext != null && isSuspended(targetContext)) { + if (fUpdatePending) { + gotoFrame(frame); + return; + } + if (DEBUG) System.out.println("retrieveFrameAddress "+frame); //$NON-NLS-1$ + fUpdatePending = true; + final IStack stack= fServicesTracker.getService(IStack.class); + final DsfExecutor executor= getSession().getExecutor(); + if (fTargetFrameContext == null) { + if (frame == 0) { + final DataRequestMonitor request= new DataRequestMonitor(executor, null) { + @Override + protected void handleCompleted() { + fUpdatePending= false; + fTargetFrameContext= getData(); + if (fTargetFrameContext != null) { + retrieveFrameAddress(targetContext, frame); + } + } + }; + executor.submit(new Runnable() { + public void run() { + stack.getTopFrame(targetContext, request); + }}); + } else { + // TODO retrieve other stack frame + } + return; + } + final DataRequestMonitor request= new DataRequestMonitor(executor, null) { + @Override + protected void handleCompleted() { + if (!isCanceled()) { + fUpdatePending= false; + final IFrameDMData frameData= getData(); + fTargetFrameData= frameData; + final IAddress address= frameData.getAddress(); + final BigInteger addressValue= address.getValue(); + if (DEBUG) System.out.println("retrieveFrameAddress done "+getAddressText(addressValue)); //$NON-NLS-1$ + asyncExec(new Runnable() { + public void run() { + if (address.getSize() * 4 > fAddressSize) { + addressSizeChanged(address.getSize() * 4); + } + if (frame == 0) { + updatePC(addressValue); + } else { + gotoFrame(frame, addressValue); + } + } + + }); + } + } + }; + executor.submit(new Runnable() { + public void run() { + stack.getFrameData(fTargetFrameContext, request); + }}); + } + } + + private void addressSizeChanged(int addressSize) { + BigInteger oldEndAddress= fEndAddress; + fEndAddress= BigInteger.ONE.shiftLeft(addressSize); + int oldAddressSize= fAddressSize; + fAddressSize= addressSize; + if (addressSize < oldAddressSize) { + fDocument.deleteDisassemblyRange(fEndAddress, oldEndAddress, true, true); + List positions= fDocument.getInvalidAddressRanges(); + List toRemove= new ArrayList(); + for (AddressRangePosition position : positions) { + if (position.fAddressOffset.compareTo(fEndAddress) >= 0) { + try { + fDocument.replace(position, position.length, ""); //$NON-NLS-1$ + fDocument.removeModelPosition(position); + toRemove.add(position); + } catch (BadLocationException exc) { + internalError(exc); + } + } else if (position.containsAddress(fEndAddress)){ + position.fAddressLength= fEndAddress.subtract(position.fAddressOffset); + } + } + positions.removeAll(toRemove); + } else if (addressSize > oldAddressSize) { + fDocument.insertInvalidAddressRange(fDocument.getLength(), 0, oldEndAddress, fEndAddress); + } else { + return; + } + if (fAddressRulerColumn != null) { + fAddressRulerColumn.setAddressSize(addressSize); + if (fComposite != null) { + fComposite.layout(true); + } + } + } + + private AddressRangePosition getPositionOfAddress(BigInteger address) { + if (address == null || address.compareTo(BigInteger.ZERO) < 0) { + return null; + } + AddressRangePosition pos = fDocument.getPositionOfAddress(address); + assert !(pos instanceof SourcePosition); + assert pos != null || address.compareTo(fStartAddress) < 0|| address.compareTo(fEndAddress) >= 0; + return pos; + } + + private BigInteger getAddressOfLine(int line) { + return fDocument.getAddressOfLine(line); + } + + private BigInteger getAddressOfOffset(int offset) { + return fDocument.getAddressOfOffset(offset); + } + + private BigInteger getAddressOfPoint(Point location) { + int offset = getOffsetOfPoint(location); + if (offset < 0) { + return PC_UNKNOWN; + } + return getAddressOfOffset(offset); + } + + private int getOffsetOfPoint(Point location) { + if (location == null) { + return -1; + } + StyledText text= fViewer.getTextWidget(); + int line= ((location.y + text.getTopPixel()) / text.getLineHeight()); + try { + return fDocument.getLineOffset(line); + } catch (BadLocationException e) { + internalError(e); + return -1; + } + } + + /** + * Passing the focus request to the viewer's control. + */ + @Override + public void setFocus() { + fViewer.getControl().setFocus(); + } + + protected void setActive(boolean active) { + if (DEBUG) System.out.println("setActive("+ active +")"); //$NON-NLS-1$ //$NON-NLS-2$ + fActive = active; + if (fActive) { + if (fRefreshAll) { + fRefreshAll = false; + refreshView(0); + } else { + doPendingPCUpdates(); + if (fTargetContext != null) { + int frame = getActiveStackFrame(); + if (frame < 0 && isSuspended(fTargetContext)) { + frame= 0; + } + if (frame != fTargetFrame) { + gotoFrame(frame); + } + } + } + } else { + fGotoAddressPending= fFocusAddress= PC_UNKNOWN; + } + firePropertyChange(PROP_ACTIVE); + } + + private int getActiveStackFrame() { + if (fTargetFrameContext != null) { + return fTargetFrameContext.getLevel(); + } + return -1; + } + + /** + * + */ + protected void updateDebugContext() { + IAdaptable debugContext= DebugUITools.getDebugContext(); + if (debugContext instanceof IDMVMContext) { + setDebugContext((IDMVMContext)debugContext); + } + } + + protected void setDebugContext(IDMVMContext vmContext) { + if (vmContext != null) { + IDMContext dmContext= vmContext.getDMContext(); + String sessionId= dmContext.getSessionId(); + if (!sessionId.equals(fDebugSessionId)) { + // switch to different session or initiate session + if (DEBUG) System.out.println("DisassemblyPart.setDebugContext() " + sessionId); //$NON-NLS-1$ + fTargetContext= null; + if (dmContext instanceof IFrameDMContext) { + IFrameDMContext frame= (IFrameDMContext) dmContext; + IExecutionDMContext executionContext= DMContexts.getAncestorOfType(frame, IExecutionDMContext.class); + if (executionContext != null) { + fTargetContext= executionContext; + fTargetFrameContext= frame; + fTargetFrame= frame.getLevel(); + } + } + if (fTargetContext != null) { + fDebugSessionId= sessionId; + if (fServicesTracker != null) { + fServicesTracker.dispose(); + } + fServicesTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), sessionId); + if (fViewer != null) { + debugContextChanged(); + } + } + } else if (dmContext instanceof IFrameDMContext) { + // switch to different frame + IFrameDMContext frame= (IFrameDMContext) dmContext; + final IDMContext[] parents= frame.getParents(); + for (IDMContext context : parents) { + if (context instanceof IExecutionDMContext) { + fTargetContext= (IExecutionDMContext) context; + fTargetFrameContext= frame; + gotoFrame(frame); + break; + } + } + } + } else if (fDebugSessionId != null) { + if (getSession() != null) { + getSession().removeServiceEventListener(this); + } + fDebugSessionId= null; + fTargetContext= null; + if (fViewer != null) { + debugContextChanged(); + } + } + } + + private void debugContextChanged() { + if (DEBUG) System.out.println("DisassemblyPart.debugContextChanged()"); //$NON-NLS-1$ + fRunnableQueue.clear(); + fUpdatePending = false; + resetViewer(); + if (fDebugSessionId != null) { + final DsfSession session= getSession(); + session.addServiceEventListener(this, null); + DsfSession.addSessionEndedListener(new SessionEndedListener() { + public void sessionEnded(DsfSession endedSsession) { + if (session == endedSsession) { + DsfSession.removeSessionEndedListener(this); + asyncExec(new Runnable() { + public void run() { + setDebugContext(null); + }}); + } + }}); + + updatePC(PC_UNKNOWN); + + if (fGotoAddressPending != PC_UNKNOWN) { + gotoAddress(fGotoAddressPending); + } + if (fGotoMarkerPending != null) { + gotoMarker(fGotoMarkerPending); + } + fViewer.addViewportListener(this); + } else { + fViewer.removeViewportListener(this); + fGotoMarkerPending = null; +// invokeLater(new Runnable() { +// public void run() { +// closePart(); +// }}); + } + updateTitle(); + updateStateDependentActions(); + firePropertyChange(PROP_CONNECTED); + firePropertyChange(PROP_SUSPENDED); + } + + @DsfServiceEventHandler + public void handleEvent(IExitedDMEvent event) { + if (event.getDMContext().equals(fTargetContext) + || DMContexts.isAncestorOf(event.getDMContext(), fTargetContext)) { + setDebugContext(null); + } + } + + @DsfServiceEventHandler + public void handleEvent(ISuspendedDMEvent event) { + if (event.getDMContext().equals(fTargetContext) + || DMContexts.isAncestorOf(event.getDMContext(), fTargetContext)) { + updatePC(PC_UNKNOWN); + firePropertyChange(PROP_SUSPENDED); + } + } + + @DsfServiceEventHandler + public void handleEvent(IResumedDMEvent event) { + if (event.getDMContext().equals(fTargetContext) + || DMContexts.isAncestorOf(event.getDMContext(), fTargetContext)) { + updatePC(PC_RUNNING); + firePropertyChange(PROP_SUSPENDED); + } + } + + private void attachBreakpointsAnnotationModel() { + IAnnotationModel annotationModel = fViewer.getAnnotationModel(); + if (annotationModel instanceof IAnnotationModelExtension) { + IAnnotationModelExtension ame= (IAnnotationModelExtension) annotationModel; + ame.addAnnotationModel(BREAKPOINT_ANNOTATIONS, new BreakpointsAnnotationModel()); + } + } + + private void refreshView(int delay) { + if (fViewer == null || fRefreshViewPending || fRefreshAll) { + return; + } + fRunnableQueue.clear(); + fRefreshViewPending = true; + final long refreshViewScheduled = System.currentTimeMillis() + delay; + final Runnable refresh = new Runnable() { + public void run() { + fRefreshViewPending = false; + long now = System.currentTimeMillis(); + if (now >= refreshViewScheduled) { + if (DEBUG) System.err.println("*** refreshing view ***"); //$NON-NLS-1$ + fFocusAddress = PC_UNKNOWN; + int targetFrame= fTargetFrame; + resetViewer(); + if (fScrollPos != null) { + fScrollPos.isDeleted = true; + } + gotoFrame(targetFrame); + } else { + refreshView((int)(refreshViewScheduled - now)); + } + }}; + if (delay > 0) { + invokeLater(delay, new Runnable() { + public void run() { + doScrollLocked(refresh); + }}); + } else { + doScrollLocked(refresh); + } + } + + private void resetViewer() { + // clear all state and cache + fPCAnnotationUpdatePending = false; + fGotoFramePending = false; + fPCAddress = fFrameAddress = PC_RUNNING; + fTargetFrame = -1; + fGotoAddressPending = fFocusAddress; + fFocusAddress = PC_UNKNOWN; + setFocusPosition(null); + fPCHistory.clear(); + fPendingPCUpdates.clear(); + fFile2Storage.clear(); + DisassemblyDocument doc= fDocument; + fDocument = createDocument(); + fViewer.setDocument(fDocument, new AnnotationModel()); + doc.dispose(); + if (fDebugSessionId != null) { + attachBreakpointsAnnotationModel(); + fDocument.insertInvalidAddressRange(0, 0, fStartAddress, fEndAddress); + } + } + + private AddressRangePosition getPCPosition(BigInteger address) { + if (address.compareTo(BigInteger.ZERO) < 0) { + // invalid address + return null; + } + AddressRangePosition pos = getPositionOfAddress(address); + if (pos == null || !pos.fValid) { + // invalid disassembly line + return null; + } + if (pos.length > 0) { + // valid disassembly line + return pos; + } + // hidden disassembly + if (!(pos instanceof DisassemblyPosition)) { + return pos; + } + String srcFile = ((DisassemblyPosition)pos).getFile(); + if (srcFile == null) { + return pos; + } + SourceFileInfo fi = fDocument.getSourceInfo(srcFile); + if (fi == null) { + return pos; + } + if (fi.fSource == null) { + if (fi.fError != null) { + // could not read source + return pos; + } + return null; + } +// if (!fi.fValid) { +// // need line info first +// return null; +// } + // determine stmt line of source range + try { + int stmtLine = ((DisassemblyPosition)pos).getLine(); + if (stmtLine < 0) { + return pos; + } + BigInteger stmtAddress = fi.fLine2Addr[stmtLine]; + if (stmtAddress.compareTo(BigInteger.ZERO) < 0) { + return pos; + } + SourcePosition srcPos = fDocument.getSourcePosition(stmtAddress); + if (srcPos == null) { + return pos; + } else if (!srcPos.fValid) { + return null; + } + assert stmtLine >= srcPos.fLine; + int baseOffset = fi.fSource.getLineOffset(srcPos.fLine); + IRegion stmtLineRegion = fi.fSource.getLineInformation(stmtLine); + int lineOffset = stmtLineRegion.getOffset(); + int offset = srcPos.offset + lineOffset - baseOffset; + int length = stmtLineRegion.getLength() + 1; + if (offset >= srcPos.offset && offset < srcPos.offset + srcPos.length) { + return new AddressRangePosition(offset, length, address, BigInteger.ZERO); + } + } catch (BadLocationException e) { + internalError(e); + } + return pos; + } + + /** + * Update the annotation indicating the given address. + * @return a position which denotes the documents position + */ + private AddressRangePosition updateAddressAnnotation(Annotation annotation, BigInteger address) { + IAnnotationModel annotationModel = fViewer.getAnnotationModel(); + annotationModel.removeAnnotation(annotation); + AddressRangePosition pos = getPCPosition(address); + if (pos != null) { + annotationModel.addAnnotation(annotation, new Position(pos.offset, Math.max(0, pos.length-1))); + } + return pos; + } + + public IBreakpoint[] getBreakpointsAtLine(int line) { + BreakpointsAnnotationModel bpModel= null; + IAnnotationModel am= fViewer.getAnnotationModel(); + if (am instanceof IAnnotationModelExtension) { + IAnnotationModelExtension ame= (IAnnotationModelExtension) am; + bpModel= (BreakpointsAnnotationModel) ame.getAnnotationModel(BREAKPOINT_ANNOTATIONS); + if (bpModel != null) { + IRegion lineRegion; + try { + lineRegion= fDocument.getLineInformation(line); + } catch (BadLocationException exc) { + return null; + } + int offset= lineRegion.getOffset(); + int length= lineRegion.getLength(); + @SuppressWarnings("unchecked") + Iterator it= bpModel.getAnnotationIterator(offset, length, true, true); + List bpList= new ArrayList(5); + final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager(); + while (it.hasNext()) { + final SimpleMarkerAnnotation annotation= it.next(); + IBreakpoint bp= bpMgr.getBreakpoint(annotation.getMarker()); + if (bp != null) { + bpList.add(bp); + } + } + if (bpList.size() > 0) { + return bpList.toArray(new IBreakpoint[bpList.size()]); + } + } + } + return null; + } + + private void gotoFrame(int frame, BigInteger address) { + if (DEBUG) System.out.println("gotoFrame " + frame + " " + getAddressText(address)); //$NON-NLS-1$ //$NON-NLS-2$ + fTargetFrame = frame; + fFrameAddress = address; + if (fTargetFrame == -1) { + fTargetFrame = getActiveStackFrame(); + if (fTargetFrame < 0 && isSuspended(fTargetContext)) { + fTargetFrame= 0; + } + if (fTargetFrame == -1) { + fGotoFramePending = false; + return; + } + } + fGotoFramePending = true; + if (frame == 0) { + fPCAddress = fFrameAddress; + } + if (fFrameAddress.compareTo(PC_UNKNOWN) == 0) { + if (!fUpdatePending) { + fGotoFramePending = false; + retrieveFrameAddress(fTargetContext, fTargetFrame); + } + return; + } + AddressRangePosition pcPos = updatePCAnnotation(); + if (pcPos == null && fFrameAddress.compareTo(BigInteger.ZERO) >= 0) { + pcPos = getPCPosition(fFrameAddress); + if (pcPos == null) { + gotoAddress(fFrameAddress); + return; + } + } + if (pcPos != null) { + if (frame == 0) { + addToPCHistory(pcPos); + } + fGotoFramePending = false; + if (fGotoAddressPending == fFrameAddress) { + fGotoAddressPending = PC_UNKNOWN; + } +// if (DEBUG) System.out.println("pc updated "+getAddressText(address)); //$NON-NLS-1$ + gotoPosition(pcPos, false); + updateVisibleArea(); + } else { + // give up + fGotoFramePending = false; + fGotoAddressPending = PC_UNKNOWN; + } + doPendingPCUpdates(); + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#isActive() + */ + public final boolean isActive() { + return fActive; + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#isConnected() + */ + public final boolean isConnected() { + return fDebugSessionId != null && fTargetContext != null; + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#isSuspended() + */ + public final boolean isSuspended() { + return isConnected() && isSuspended(fTargetContext); + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#getTextViewer() + */ + public final ISourceViewer getTextViewer() { + return fViewer; + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#addRulerContextMenuListener(org.eclipse.jface.action.IMenuListener) + */ + public final void addRulerContextMenuListener(IMenuListener listener) { + fRulerContextMenuListeners.add(listener); + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart#removeRulerContextMenuListener(org.eclipse.jface.action.IMenuListener) + */ + public final void removeRulerContextMenuListener(IMenuListener listener) { + fRulerContextMenuListeners.remove(listener); + } + + private boolean isSuspended(IExecutionDMContext targetContext) { + return getRunControl().isSuspended(targetContext); + } + + private IRunControl getRunControl() { + return getService(IRunControl.class); + } + + /*default*/ DsfSession getSession() { + return DsfSession.getSession(fDebugSessionId); + } + + /*default*/ V getService(Class serviceClass) { + if (fServicesTracker != null) { + return fServicesTracker.getService(serviceClass); + } + return null; + } + + /*default*/ IFrameDMContext getTargetFrameContext() { + return fTargetFrameContext; + } + + /** + * Schedule the retrieval of a module time stamp for the given address. + * Should return a Long object in case the value was computed, + * another object to be waited on if the retrieval is in progress, null + * if no time stamp could be retrieved. + * + * @param address + * @return Long, Object or null + */ + synchronized Object retrieveModuleTimestamp(BigInteger address) { + // TLETODO [disassembly] retrieve and cache module time stamp + return null; + } + + private void setFocusPosition(Position pcPos) { + if (fFocusPos != null) { + fDocument.removePosition(fFocusPos); + fFocusPos = null; + } + if (pcPos != null) { + fFocusPos = new Position(pcPos.offset, pcPos.length); + try { + fDocument.addPosition(fFocusPos); + } catch (BadLocationException e) { + internalError(e); + } + } else { + fFocusAddress = PC_UNKNOWN; + } + } + + private void doPendingPCUpdates() { + if (fPendingPCUpdates.isEmpty()) { + return; + } + BigInteger pc; + do { + pc = fPendingPCUpdates.remove(0); + if (pc.compareTo(BigInteger.ZERO) >= 0) { + break; + } + } while (!fPendingPCUpdates.isEmpty()); + gotoFrame(0, pc); + } + + private void addToPCHistory(AddressRangePosition pcPos) { + if (DEBUG) System.out.println("addToPCHistory "+getAddressText(pcPos.fAddressOffset)); //$NON-NLS-1$ + if (fPCHistorySizeMax <= 1) { + return; + } + AddressRangePosition first = null; + if (fPCHistory.size() > 0) { + first = fPCHistory.getFirst(); + if (first.fAddressOffset == pcPos.fAddressOffset) { + if (first.offset != pcPos.offset || first.length != pcPos.length) { + fPCHistory.removeFirst(); + fViewer.invalidateTextPresentation(first.offset, first.length); + } else { + return; + } + } + } + // clone and add + pcPos = new AddressRangePosition(pcPos.offset, pcPos.length, pcPos.fAddressOffset, BigInteger.ZERO); + fPCHistory.addFirst(pcPos); + try { + fDocument.addPosition(pcPos); + } catch (BadLocationException e) { + internalError(e); + } + // limit to max size + if (fPCHistory.size() > fPCHistorySizeMax) { + AddressRangePosition last = fPCHistory.removeLast(); + fDocument.removePosition(last); + fViewer.invalidateTextPresentation(last.offset, last.length); + } + // redraw + for (Iterator it=fPCHistory.iterator(); it.hasNext();) { + AddressRangePosition pos = it.next(); + fViewer.invalidateTextPresentation(pos.offset, pos.length); + } + } + + /** + * Update current pc. If a pc update is currently under way, adds this + * address to a list of pending pc updates. + * + * @param pc Current pc address. -1 means retrieve pc from top frame, -2 + * means target resumed + */ + private void updatePC(BigInteger pc) { + if (!fPendingPCUpdates.isEmpty()) { + BigInteger last = fPendingPCUpdates.get(fPendingPCUpdates.size()-1); + if (last.compareTo(BigInteger.ZERO) < 0) { + fPendingPCUpdates.remove(fPendingPCUpdates.size()-1); + } + } + fPendingPCUpdates.add(pc); + if (fPendingPCUpdates.size() > fPCHistorySizeMax) { + if (!fActive) { + // if not active, we can savely remove + // the pc updates before the history range + fPendingPCUpdates.remove(0); + } + // we ignore the current goto frame request + // and continue with the pending updates + fGotoFramePending = false; + } + if (fActive) { + if (fGotoFramePending) { + if (!fUpdatePending) { + gotoFrame(0, fFrameAddress); + } + } else { + doPendingPCUpdates(); + } + } + } + + private AddressRangePosition updatePCAnnotation() { + if (fUpdatePending) { + fPCAnnotationUpdatePending = true; + return null; + } + AddressRangePosition pos; + if (fTargetFrame == 0) { + // clear secondary + updateAddressAnnotation(fSecondaryPCAnnotation, PC_UNKNOWN); + // set primary + pos = updateAddressAnnotation(fPCAnnotation, fPCAddress); + } else { + // clear primary + updateAddressAnnotation(fPCAnnotation, PC_UNKNOWN); + // set secondary + pos = updateAddressAnnotation(fSecondaryPCAnnotation, fFrameAddress); + } + fPCAnnotationUpdatePending = pos == null && fFrameAddress.compareTo(BigInteger.ZERO) >= 0; + return pos; + } + + private void scheduleDoPending() { + if (!fUpdatePending && !fDoPendingPosted) { + fDoPendingPosted = true; + invokeLater(new Runnable() { + public void run() { + doPending(); + fDoPendingPosted = false; + } + }); + } + } + + private void doPending() { + if (fViewer == null || fDocument == null) { + return; + } + if (fUpdateSourcePending) { + updateInvalidSource(); + } + boolean sourceValid= fDocument.getInvalidSource().isEmpty(); + if (sourceValid || fShowDisassembly) { + if (fGotoFramePending) { + gotoFrame(fTargetFrame, fFrameAddress); + } + } + if (sourceValid) { + if (fGotoAddressPending != PC_UNKNOWN) { + gotoAddress(fGotoAddressPending); + } else if (fGotoMarkerPending != null) { + gotoMarker(fGotoMarkerPending); + } + if (fPCAnnotationUpdatePending && !fGotoFramePending) { + updatePCAnnotation(); + } + if (fUpdateTitlePending) { + updateTitle(); + } + } + } + + /** + * Safely run given runnable in a state when no update is pending. + * Delays execution by 10 ms if update is currently pending. + * @param doit + */ + private void doScrollLocked(final Runnable doit) { + if (fViewer == null || fDebugSessionId == null) { + // disposed + return; + } + if (!fActive) { + // refresh all when becoming active again + fRefreshViewPending= false; + fRefreshAll = true; + return; + } + if (doit != null) { + fRunnableQueue.add(doit); + } + if (fUpdatePending) { + if (fRunnableQueue.size() == 1) { + Runnable doitlater = new Runnable() { + public void run() { + doScrollLocked(null); + }}; + invokeLater(doitlater); + } + } else { + fUpdatePending = true; + lockScroller(); + try { + ArrayList copy = new ArrayList(fRunnableQueue); + fRunnableQueue.clear(); + for (Iterator iter = copy.iterator(); iter.hasNext();) { + Runnable doitnow = iter.next(); + try { + doitnow.run(); + } catch(Exception e) { + internalError(e); + } + } + } finally { + fUpdatePending = false; + unlockScroller(); + doPending(); + updateVisibleArea(); + } + } + } + + private void lockScroller() { + assert fScrollPos == null; + if (isOpcodeRulerVisible()) { + fRedrawControl = fViewer.getControl(); + } else { + fRedrawControl = fViewer.getTextWidget(); + } + fRedrawControl.setRedraw(false); + try { + int topOffset = fViewer.getTopIndexStartOffset(); + int topIndex = fViewer.getTopIndex(); + int bottomIndex = fViewer.getBottomIndex(); + int bottomOffset = fViewer.getBottomIndexEndOffset(); + int focusLine; + int focusOffset; + if (fFocusPos != null && fFocusPos.isDeleted) { + fFocusPos = null; + } + if (fFocusPos != null && fFocusPos.offset >= topOffset && fFocusPos.offset <= bottomOffset) { + focusOffset = fFocusPos.offset; + focusLine = fDocument.getLineOfOffset(focusOffset); + } else { + focusLine = Math.max(0, (topIndex + bottomIndex) / 2); + focusOffset = fDocument.getLineOffset(focusLine); + AddressRangePosition pos = fDocument.getDisassemblyPosition(focusOffset); + if (pos != null && !pos.fValid) { + // don't lock position of invalid range + focusOffset = pos.offset+pos.length; + focusLine = fDocument.getLineOfOffset(focusOffset); + } + } + fScrollPos = new Position(focusOffset); + fScrollLine = focusLine - topIndex; + fDocument.addPosition(fScrollPos); + } catch (BadLocationException e) { + // should not happen + internalError(e); + } + } + + private void unlockScroller() { + try { + if (fScrollPos == null) { + return; + } + if (fScrollPos.isDeleted) { + fScrollPos.isDeleted = false; + if (fScrollPos.offset >= fDocument.getLength()) { + fScrollPos.offset = 0; + fScrollLine = 0; + } + } + if (fFocusPos != null && (fFocusPos.isDeleted || fFocusPos.length == 0)) { + if (fFocusAddress.compareTo(BigInteger.ZERO) >= 0) { + fGotoAddressPending = fFocusAddress; + setFocusPosition(getPositionOfAddress(fFocusAddress)); + } + } + int topLine = fDocument.getLineOfOffset(fScrollPos.offset) - fScrollLine; + // limit text size + int lineCount = fDocument.getNumberOfLines(); + if (lineCount > fgHighWaterMark*fBufferZone) { + int startLine = Math.max(0, topLine-fgLowWaterMark/2*fBufferZone); + int endLine = Math.min(lineCount-1, topLine+fgLowWaterMark/2*fBufferZone); + fDocument.deleteLineRange(endLine, lineCount-1); + fDocument.deleteLineRange(0, startLine); + } + int lineHeight = fViewer.getTextWidget().getLineHeight(); + int topPixel = topLine * lineHeight; + if (Math.abs(fViewer.getTextWidget().getTopPixel() - topPixel) >= lineHeight) { + fViewer.setTopIndex(topLine); + } + } catch (BadLocationException e) { + // should not happen + internalError(e); + } finally { + if (fScrollPos != null && fDocument != null) { + fDocument.removePosition(fScrollPos); + fScrollPos = null; + } + if (fViewer != null) { + fRedrawControl.setRedraw(true); + getVerticalRuler().update(); + getOverviewRuler().update(); + } + } + } + + private void insertSource(SourcePosition pos) { + if (!fShowSource) { + fDocument.insertSource(pos, "", pos.fLine, true); //$NON-NLS-1$ + return; + } + SourceFileInfo fi = pos.fFileInfo; + BigInteger address = pos.fAddressOffset; + int lineNr = pos.fLine; + if (fi.fError != null) { + // handled below + } else if (fi.fValid) { +// assert fi.fLinesNode.isValid(); + Addr2Line a2l = fi.fAddr2Line[Addr2Line.hash(address, fi.fAddr2Line.length)]; + while (a2l != null && !a2l.addr.equals(address)) + a2l = a2l.next; + if (a2l != null) { + int first = a2l.first; + int line; + for (line = first; line <= a2l.last; ++line) { + if (!fi.fLine2Addr[line].equals(address)) { + if (line > first) { + String source = fi.getLines(first, line-1); + pos = fDocument.insertSource(pos, source, first, false); + } + first = line+1; + } + } + if (line > first) { + String source = fi.getLines(first, line-1); + fDocument.insertSource(pos, source, first, true); + if (source.length() == 0) { + fDocument.removeSourcePosition(pos); + } + } else if (first > a2l.first) { + fDocument.insertSource(pos, "", first, true); //$NON-NLS-1$ + fDocument.removeSourcePosition(pos); + } + } else { + // no source at all + fDocument.insertSource(pos, "", lineNr, true); //$NON-NLS-1$ + fDocument.removeSourcePosition(pos); + } + } else if (fi.fLinesNode == null) { + // TLETODO [disassembly] asynchronous line info + if (fi.fSource != null) { + fi.fError= new Error(); + } + } + if (fi.fError != null && !pos.fValid) { + if (fi.fSource != null) { + if (fi.fSource != null && lineNr >= 0 && lineNr < fi.fSource.getNumberOfLines()) { + fi.fStartAddress = fi.fStartAddress.min(pos.fAddressOffset); + fi.fEndAddress = fi.fEndAddress.max(pos.fAddressOffset.add(pos.fAddressLength)); + if (fi.fLine2Addr[lineNr] == null || fi.fLine2Addr[lineNr].compareTo(BigInteger.ZERO) < 0) { + fi.fLine2Addr[lineNr] = pos.fAddressOffset; + String sourceLine = fi.getLine(lineNr); + fDocument.insertSource(pos, sourceLine, lineNr, true); + } else if (fi.fLine2Addr[lineNr].compareTo(pos.fAddressOffset) > 0) { + SourcePosition oldPos = fDocument.getSourcePosition(fi.fLine2Addr[lineNr]); + if (oldPos != null) { + try { + fDocument.replace(oldPos, oldPos.length, null); + } catch (BadLocationException e) { + internalError(e); + } + fDocument.removeSourcePosition(oldPos); + } + fi.fLine2Addr[lineNr] = pos.fAddressOffset; + String sourceLine = fi.getLine(lineNr); + fDocument.insertSource(pos, sourceLine, lineNr, true); + } else if (fi.fLine2Addr[lineNr].equals(pos.fAddressOffset)) { + String sourceLine = fi.getLine(lineNr); + fDocument.insertSource(pos, sourceLine, lineNr, true); + } else { + fDocument.insertSource(pos, "", lineNr, true); //$NON-NLS-1$ + fDocument.removeSourcePosition(pos); + } + } + } else { + // no source at all + fDocument.insertSource(pos, "", lineNr, true); //$NON-NLS-1$ + fDocument.removeSourcePosition(pos); + } + } + } + + private void updateTitle() { + if (fDebugSessionId == null) { + String descr = DisassemblyMessages.Disassembly_message_notConnected; + String title = getConfigurationElement().getAttribute("name"); //$NON-NLS-1$ + setPartName(title); + setContentDescription(descr); + setTitleToolTip(title); + } else { + // TLETODO Proper content description + setContentDescription(""); //$NON-NLS-1$ + } + } + + private boolean isDissemblyMixedModeOn() { + // TLETODO [disassembly] mixed mode on/off + return true; + } + + /** + * Close this part + */ + protected abstract void closePart(); + + /* + * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation) + */ + public void applyTextPresentation(TextPresentation textPresentation) { + IRegion coverage = textPresentation.getExtent(); + if (coverage == null) { + coverage= new Region(0, fDocument.getLength()); + } + int startOffset = coverage.getOffset(); + int length = coverage.getLength(); + int endOffset = startOffset + length; + Iterator it; + try { + // make sure we start with first overlapping position + AddressRangePosition pos = fDocument.getModelPosition(startOffset); + assert pos != null; + if (pos == null) { + return; + } + it = fDocument.getPositionIterator(DisassemblyDocument.CATEGORY_MODEL, pos.offset); + } catch (BadPositionCategoryException e) { + return; + } catch (BadLocationException e) { + return; + } + ArrayList styleRanges = new ArrayList(); + while(it.hasNext()) { + AddressRangePosition pos = (AddressRangePosition)it.next(); + if (pos.offset >= endOffset) { + break; + } + if (pos.offset+pos.length <= startOffset) { + continue; + } + if (pos.fValid && pos.length > 0) { + if (pos instanceof DisassemblyPosition) { + DisassemblyPosition disPos = (DisassemblyPosition)pos; + styleRanges.add(new StyleRange(pos.offset, disPos.length, fInstructionColor, null, SWT.NULL)); + } else if (pos instanceof ErrorPosition) { + styleRanges.add(new StyleRange(pos.offset, pos.length, fErrorColor, null, SWT.NULL)); + } else if (pos instanceof LabelPosition) { + styleRanges.add(new StyleRange(pos.offset, pos.length, fLabelColor, null, SWT.BOLD)); + } else if (pos instanceof SourcePosition) { + SourcePosition srcPos = (SourcePosition)pos; + TextPresentation presentation = null; + if (srcPos.fFileInfo.fSource != null) { + presentation = srcPos.fFileInfo.getPresentation(srcPos.fFileInfo.getRegion(srcPos.fLine, pos.length)); + } + if (presentation != null) { + // clip result window to coverage + int start = Math.max(startOffset, srcPos.offset); + int end = Math.min(endOffset, srcPos.offset + srcPos.length); + int srcOffset = srcPos.fFileInfo.getLineOffset(srcPos.fLine); + int clipOffset = start - srcPos.offset; + presentation.setResultWindow(new Region(srcOffset + clipOffset, end-start)); + for (Iterator iter = presentation.getNonDefaultStyleRangeIterator(); iter.hasNext();) { + StyleRange styleRange = iter.next(); + styleRange.start += srcPos.offset + clipOffset; + styleRanges.add(styleRange); + } + } else { + styleRanges.add(new StyleRange(pos.offset, pos.length, fSourceColor, null, SWT.NULL)); + } + } + } + } + if (styleRanges.size() > 0) { + for (Iterator iter = styleRanges.iterator(); iter.hasNext();) { + textPresentation.addStyleRange(iter.next()); + } + } + // update pc history trail + if (fPCHistory.size() > 1) { + HSL hsv = new HSL(fPCAnnotationRGB); + double luminanceStep = (1-hsv.luminance)/(fPCHistorySizeMax+1); + hsv.luminance = 1 - luminanceStep * (fPCHistorySizeMax - fPCHistory.size()); + for (ListIterator listIt = fPCHistory.listIterator(fPCHistory.size()); listIt.hasPrevious();) { + AddressRangePosition pcPos = listIt.previous(); + hsv.luminance -= luminanceStep; + if (pcPos.isDeleted) { + listIt.remove(); + continue; + } + if (!pcPos.fValid) { + continue; + } + if (pcPos.overlapsWith(startOffset, length)) { + RGB rgb = hsv.toRGB(); + Color pcColor = getSharedColors().getColor(rgb); + Color textColor = null; + // experimental: if color is dark, use white (background) as text color +// Color textColor = hsv.luminance < 0.7 ? fViewer.getTextWidget().getBackground() : null; + textPresentation.mergeStyleRange(new StyleRange(pcPos.offset, pcPos.length, textColor, pcColor)); + } + } + } + } + + + private IBreakpoint insertBreakpoint(int line, boolean edit) throws CoreException { + SourcePosition srcPos = null; + try { + int lineOffset = fDocument.getLineOffset(line); + srcPos = fDocument.getSourcePosition(lineOffset); + } catch (BadLocationException e) { + // should not happen, but its safe to ignore anyway + } + boolean lineBreakpoint = srcPos != null && srcPos.length > 0; + + IResource resource; + ICBreakpoint bp; + + if (lineBreakpoint) { + SourceFileInfo srcInfo = srcPos.fFileInfo; + String filePath = null; + resource = (IResource)srcInfo.fFile.getAdapter(IResource.class); + if (resource != null) { + final IPath location= resource.getLocation(); + if (location == null) { + return null; + } + filePath = location.toOSString(); + } else { + resource = ResourcesPlugin.getWorkspace().getRoot(); + filePath = srcInfo.fFile.getFullPath().toOSString(); + } + BigInteger address = srcPos.fAddressOffset; + AddressRangePosition pos = fDocument.getDisassemblyPosition(address); + int srcLine = -1; + if (pos instanceof DisassemblyPosition) { + srcLine = ((DisassemblyPosition)pos).getLine(); + } + bp= CDIDebugModel.createLineBreakpoint(filePath, resource, srcLine + 1, true, 0, "", true); //$NON-NLS-1$ + } else { + resource = ResourcesPlugin.getWorkspace().getRoot(); + BigInteger address = getAddressOfLine(line); + bp= CDIDebugModel.createAddressBreakpoint(null, null, resource, new Addr64(address), true, 0, "", true); //$NON-NLS-1$ + } + + return bp; + } + + private AddressRangePosition insertSource(AddressRangePosition pos, BigInteger address, final String file, int lineNr) { + Object sourceElement = null; + if (fFile2Storage.containsKey(file)) { + sourceElement = fFile2Storage.get(file); + } else { + final ISourceLookup lookup= getService(ISourceLookup.class); + final ISourceLookupDMContext ctx= DMContexts.getAncestorOfType(fTargetContext, ISourceLookupDMContext.class); + final DsfExecutor executor= getSession().getExecutor(); + Query query= new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + final DataRequestMonitor request= new DataRequestMonitor(executor, rm) { + @Override + protected void handleSuccess() { + rm.setData(getData()); + rm.done(); + } + }; + lookup.getSource(ctx, file, request); + } + }; + try { + getSession().getExecutor().execute(query); + sourceElement= query.get(); + } catch (InterruptedException exc) { + internalError(exc); + } catch (ExecutionException exc) { + internalError(exc); + } + if (sourceElement instanceof File) { + sourceElement = new LocalFileStorage((File)sourceElement); + } + if (sourceElement instanceof IStorage) { + fFile2Storage.put(file, sourceElement); + } else { + fFile2Storage.put(file, null); + logWarning(DisassemblyMessages.Disassembly_log_error_locateFile+file, null); + } + } + if (sourceElement instanceof IStorage) { + SourceFileInfo fi = fDocument.getSourceInfo((IStorage)sourceElement); + if (fi == null) { + IStorage storage = (IStorage)sourceElement; + Display display = getSite().getShell().getDisplay(); + Runnable done = new SourceColorerJob(display, storage, this); + fi = fDocument.createSourceInfo(file, storage, done); + EditionFinderJob editionJob = null; + if (storage instanceof IFile) { + editionJob = new EditionFinderJob(fi, address, this); + editionJob.schedule(); + } + fi.fReadingJob.schedule(); + } + pos = fDocument.insertInvalidSource(pos, address, fi, lineNr); + } + return pos; + } + + private void disassemblyModeChanged(boolean isDisassemblyOn) { + if (fShowDisassembly == isDisassemblyOn) { + return; + } + if (fShowDisassembly && !fSourceOnlyMode) { + // if not in source-only mode, do not update if disassembly mode is disabled + return; + } + fShowDisassembly = isDisassemblyOn; + if (!fShowDisassembly) { + sourceModeChanged(true); + } + fActionToggleSource.update(); + Runnable doit = new Runnable() { + public void run() { + fDocument.invalidateDisassemblyWithSource(!fShowDisassembly); + fGotoFramePending = true; + }}; + doScrollLocked(doit); + } + + /** + * Turn on/off source mode. + * @param isSourceModeOn + */ + private void sourceModeChanged(boolean isSourceModeOn) { + if (fShowSource == isSourceModeOn) { + return; + } + fShowSource = isSourceModeOn; + fActionToggleSource.update(); + fDocument.invalidateSource(); + if (!fShowSource && !fShowDisassembly) { + disassemblyModeChanged(true); + } else { + fPCAnnotationUpdatePending = true; + updateInvalidSource(); + } + } + + public static BigInteger decodeAddress(String string) { + if (string.startsWith("0x")) { //$NON-NLS-1$ + return new BigInteger(string.substring(2), 16); + } + return new BigInteger(string); + } + + private static String getAddressText(BigInteger address) { + if (address == null) { + return ""; //$NON-NLS-1$ + } + if (address.compareTo(BigInteger.ZERO) < 0) { + return address.toString(); + } + String hex = address.toString(16); + return "0x" + "0000000000000000".substring(hex.length() + (address.bitLength() <= 32 ? 8 : 0)) + hex; //$NON-NLS-1$ //$NON-NLS-2$ + } + + static void internalError(Throwable e) { + if (DEBUG) { + System.err.println("Disassembly: Internal error"); //$NON-NLS-1$ + e.printStackTrace(); + } + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java new file mode 100644 index 00000000000..5645a394360 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java @@ -0,0 +1,985 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Anton Leherbauer (Wind River Systems) + *******************************************************************************/ + +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.util.Arrays; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextListener; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension; +import org.eclipse.jface.text.ITextViewerExtension5; +import org.eclipse.jface.text.IViewportListener; +import org.eclipse.jface.text.TextEvent; +import org.eclipse.jface.text.source.CompositeRuler; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IVerticalRulerColumn; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; + +/** + * Vertical ruler column for use with disassembly parts. + *

+ * Derived from {@link org.eclipse.jface.text.source.LineNumberRulerColumn}. + *

+ */ +public class DisassemblyRulerColumn implements IVerticalRulerColumn { + protected final static String DOTS = "......................................................................"; //$NON-NLS-1$ + protected final static String SPACES = " "; //$NON-NLS-1$ + + /** + * Internal listener class. + */ + class InternalListener implements IViewportListener, ITextListener, ISelectionChangedListener { + + /* + * @see IViewportListener#viewportChanged(int) + */ + public void viewportChanged(int verticalPosition) { + if (verticalPosition != fScrollPos) + redraw(); + } + + /* + * @see ITextListener#textChanged(TextEvent) + */ + public void textChanged(TextEvent event) { + + if (updateNumberOfDigits()) { + computeIndentations(); + layout(event.getViewerRedrawState()); + return; + } + + if (!event.getViewerRedrawState()) + return; + + if (fSensitiveToTextChanges || event.getDocumentEvent() == null) + postRedraw(); + + } + + /* + * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) + */ + public void selectionChanged(SelectionChangedEvent event) { + postRedraw(); + } + } + + /** + * Handles all the mouse interaction in this line number ruler column. + */ + class MouseHandler implements MouseListener, MouseMoveListener, MouseTrackListener { + + /** The cached view port size */ + private int fCachedViewportSize; + /** The area of the line at which line selection started */ + private IRegion fStartLine; + /** The number of the line at which line selection started */ + private int fStartLineNumber; + /** The auto scroll direction */ + private int fAutoScrollDirection; + + /* + * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) + */ + public void mouseUp(MouseEvent event) { + // see bug 45700 + if (event.button == 1) { + stopSelecting(); + stopAutoScroll(); + postRedraw(); + } + } + + /* + * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDown(MouseEvent event) { + fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y); + // see bug 45700 + if (event.button == 1) { + startSelecting(); + } + } + + /* + * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDoubleClick(MouseEvent event) { + fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y); + stopSelecting(); + stopAutoScroll(); + } + + /* + * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent) + */ + public void mouseMove(MouseEvent event) { + if (!autoScroll(event)) { + int newLine = fParentRuler.toDocumentLineNumber(event.y); + expandSelection(newLine); + } + } + + /* + * @see org.eclipse.swt.events.MouseTrackListener#mouseEnter(org.eclipse.swt.events.MouseEvent) + */ + public void mouseEnter(MouseEvent event) { + } + + /* + * @see org.eclipse.swt.events.MouseTrackListener#mouseExit(org.eclipse.swt.events.MouseEvent) + */ + public void mouseExit(MouseEvent event) { + } + + /* + * @see org.eclipse.swt.events.MouseTrackListener#mouseHover(org.eclipse.swt.events.MouseEvent) + */ + public void mouseHover(MouseEvent event) { + } + + /** + * Called when line drag selection started. Adds mouse move and track + * listeners to this column's control. + */ + private void startSelecting() { + try { + + // select line + IDocument document = fCachedTextViewer.getDocument(); + fStartLineNumber = fParentRuler.getLineOfLastMouseButtonActivity(); + fStartLine = document.getLineInformation(fStartLineNumber); + fCachedTextViewer.setSelectedRange(fStartLine.getOffset(), fStartLine.getLength()); + fCachedViewportSize = getVisibleLinesInViewport(); + + // prepare for drag selection + fCanvas.addMouseMoveListener(this); + fCanvas.addMouseTrackListener(this); + + } catch (BadLocationException x) { + } + } + + /** + * Called when line drag selection stopped. Removes all previously + * installed listeners from this column's control. + */ + private void stopSelecting() { + // drag selection stopped + fCanvas.removeMouseMoveListener(this); + fCanvas.removeMouseTrackListener(this); + } + + /** + * Expands the line selection from the remembered start line to the + * given line. + * + * @param lineNumber + * the line to which to expand the selection + */ + private void expandSelection(int lineNumber) { + try { + + IDocument document = fCachedTextViewer.getDocument(); + IRegion lineInfo = document.getLineInformation(lineNumber); + + int start = Math.min(fStartLine.getOffset(), lineInfo.getOffset()); + int end = Math.max(fStartLine.getOffset() + fStartLine.getLength(), lineInfo.getOffset() + + lineInfo.getLength()); + + if (lineNumber < fStartLineNumber) + fCachedTextViewer.setSelectedRange(end, start - end); + else + fCachedTextViewer.setSelectedRange(start, end - start); + + } catch (BadLocationException x) { + } + } + + /** + * Called when auto scrolling stopped. Clears the auto scroll direction. + */ + private void stopAutoScroll() { + fAutoScrollDirection = SWT.NULL; + } + + /** + * Called on drag selection. + * + * @param event + * the mouse event caught by the mouse move listener + * @return true if scrolling happened, false + * otherwise + */ + private boolean autoScroll(MouseEvent event) { + Rectangle area = fCanvas.getClientArea(); + + if (event.y > area.height) { + autoScroll(SWT.DOWN); + return true; + } + + if (event.y < 0) { + autoScroll(SWT.UP); + return true; + } + + stopAutoScroll(); + return false; + } + + /** + * Scrolls the viewer into the given direction. + * + * @param direction + * the scroll direction + */ + private void autoScroll(int direction) { + + if (fAutoScrollDirection == direction) + return; + + final int TIMER_INTERVAL = 5; + final Display display = fCanvas.getDisplay(); + Runnable timer = null; + switch (direction) { + case SWT.UP: + timer = new Runnable() { + public void run() { + if (fAutoScrollDirection == SWT.UP) { + int top = getInclusiveTopIndex(); + if (top > 0) { + fCachedTextViewer.setTopIndex(top - 1); + expandSelection(top - 1); + display.timerExec(TIMER_INTERVAL, this); + } + } + } + }; + break; + case SWT.DOWN: + timer = new Runnable() { + public void run() { + if (fAutoScrollDirection == SWT.DOWN) { + int top = getInclusiveTopIndex(); + fCachedTextViewer.setTopIndex(top + 1); + expandSelection(top + 1 + fCachedViewportSize); + display.timerExec(TIMER_INTERVAL, this); + } + } + }; + break; + } + + if (timer != null) { + fAutoScrollDirection = direction; + display.timerExec(TIMER_INTERVAL, timer); + } + } + + /** + * Returns the viewer's first visible line, even if only partially + * visible. + * + * @return the viewer's first visible line + */ + private int getInclusiveTopIndex() { + if (fCachedTextWidget != null && !fCachedTextWidget.isDisposed()) { + int top = fCachedTextViewer.getTopIndex(); + if ((fCachedTextWidget.getTopPixel() % fCachedTextWidget.getLineHeight()) != 0) + --top; + return top; + } + return -1; + } + } + + /** This column's parent ruler */ + private CompositeRuler fParentRuler; + /** Cached text viewer */ + private ITextViewer fCachedTextViewer; + /** Cached text widget */ + private StyledText fCachedTextWidget; + /** The columns canvas */ + private Canvas fCanvas; + /** Cache for the actual scroll position in pixels */ + private int fScrollPos; + /** The drawable for double buffering */ + private Image fBuffer; + /** The internal listener */ + private InternalListener fInternalListener = new InternalListener(); + /** The font of this column */ + private Font fFont; + /** The indentation cache */ + private int[] fIndentation; + /** Indicates whether this column reacts on text change events */ + private boolean fSensitiveToTextChanges = false; + /** The foreground color */ + private Color fForeground; + /** The background color */ + private Color fBackground; + /** Cached number of displayed digits */ + private int fCachedNumberOfDigits = -1; + /** Flag indicating whether a relayout is required */ + private boolean fRelayoutRequired = false; + /** + * Redraw runnable lock + */ + private Object fRunnableLock = new Object(); + /** + * Redraw runnable state + */ + private boolean fIsRunnablePosted = false; + /** + * Redraw runnable + */ + private Runnable fRunnable = new Runnable() { + public void run() { + synchronized (fRunnableLock) { + fIsRunnablePosted = false; + } + redraw(); + } + }; + private boolean fAlignRight; + private boolean fPaintStyleBackground; + private boolean fPaintSelectionBackground; + + /** + * Constructs a new vertical ruler column. + * + */ + public DisassemblyRulerColumn() { + this(SWT.LEFT); + // default constructor + } + + public DisassemblyRulerColumn(int align) { + this(align, true, false); + } + + public DisassemblyRulerColumn(int align, boolean paintSelection, boolean paintStyle) { + fAlignRight = (align & SWT.RIGHT) != 0; + fPaintSelectionBackground = paintSelection; + fPaintStyleBackground = paintStyle; + } + + /** + * Sets the foreground color of this column. + * + * @param foreground + * the foreground color + */ + public void setForeground(Color foreground) { + fForeground = foreground; + } + + /** + * Returns the foreground color being used to print the line numbers. + * + * @return the configured foreground color + */ + protected Color getForeground() { + return fForeground; + } + + /** + * Sets the background color of this column. + * + * @param background + * the background color + */ + public void setBackground(Color background) { + fBackground = background; + if (fCanvas != null && !fCanvas.isDisposed()) + fCanvas.setBackground(getBackground(fCanvas.getDisplay())); + } + + /** + * Returns the System background color for list widgets. + * + * @param display + * the display + * @return the System background color for list widgets + */ + protected Color getBackground(Display display) { + if (fBackground == null) + return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND); + return fBackground; + } + + /* + * @see IVerticalRulerColumn#getControl() + */ + public Control getControl() { + return fCanvas; + } + + /* + * @see IVerticalRuleColumnr#getWidth + */ + public int getWidth() { + return fIndentation[0]; + } + + /** + * Computes the number of digits to be displayed. Returns true + * if the number of digits changed compared to the previous call of this + * method. If the method is called for the first time, the return value is + * also true. + * + * @return whether the number of digits has been changed + */ + protected boolean updateNumberOfDigits() { + if (fCachedTextViewer == null) + return false; + + int digits = computeNumberOfCharacters(); + + if (fCachedNumberOfDigits != digits) { + fCachedNumberOfDigits = digits; + return true; + } + + return false; + } + + /** + * Does the real computation of the number of characters. The default + * implementation computes the number of digits for the line number. + * Subclasses may override this method if they need extra space on the ruler. + * + * @return the number of characters to be displayed on the ruler. + */ + protected int computeNumberOfCharacters() { + IDocument document = fCachedTextViewer.getDocument(); + int lines= document == null ? 0 : document.getNumberOfLines(); + + int digits= 2; + while (lines > Math.pow(10, digits) - 1) { + ++digits; + } + return digits; + } + + /** + * Layouts the enclosing viewer to adapt the layout to changes of the size + * of the individual components. + * + * @param redraw + * true if this column can be redrawn + */ + protected void layout(boolean redraw) { + if (!redraw) { + fRelayoutRequired= true; + return; + } + + fRelayoutRequired= false; + if (fCachedTextViewer instanceof ITextViewerExtension) { + ITextViewerExtension extension= (ITextViewerExtension) fCachedTextViewer; + Control control= extension.getControl(); + if (control instanceof Composite && !control.isDisposed()) { + Composite composite= (Composite) control; + composite.layout(true); + } + } + } + + /** + * Computes the indentations for the given font and stores them in + * fIndentation. + */ + protected void computeIndentations() { + if (fCanvas == null) + return; + + GC gc= new GC(fCanvas); + try { + + gc.setFont(fCanvas.getFont()); + + fIndentation= new int[fCachedNumberOfDigits + 1]; + char[] digitStr= new char[fCachedNumberOfDigits + 1]; + Arrays.fill(digitStr, '9'); + Point p= gc.stringExtent(new String(digitStr, 0, fCachedNumberOfDigits + 1)); + fIndentation[0]= p.x; + + for (int i= 1; i <= fCachedNumberOfDigits; i++) { + p= gc.stringExtent(new String(digitStr, 0, i)); + fIndentation[i]= fIndentation[0] - p.x; + } + + } finally { + gc.dispose(); + } + } + + /* + * @see IVerticalRulerColumn#createControl(CompositeRuler, Composite) + */ + public Control createControl(CompositeRuler parentRuler, Composite parentControl) { + + fParentRuler= parentRuler; + fCachedTextViewer= parentRuler.getTextViewer(); + fCachedTextWidget= fCachedTextViewer.getTextWidget(); + + fCanvas= new Canvas(parentControl, SWT.NONE); + fCanvas.setBackground(getBackground(fCanvas.getDisplay())); + fCanvas.setForeground(fForeground); + + fCanvas.addPaintListener(new PaintListener() { + public void paintControl(PaintEvent event) { + if (fCachedTextViewer != null) + doubleBufferPaint(event.gc); + } + }); + + fCanvas.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + handleDispose(); + fCachedTextViewer= null; + fCachedTextWidget= null; + } + }); + + fCanvas.addMouseListener(new MouseHandler()); + + if (fCachedTextViewer != null) { + + fCachedTextViewer.addViewportListener(fInternalListener); + fCachedTextViewer.addTextListener(fInternalListener); + fCachedTextViewer.getSelectionProvider().addSelectionChangedListener(fInternalListener); + + if (fFont == null) { + if (fCachedTextWidget != null && !fCachedTextWidget.isDisposed()) + fFont= fCachedTextWidget.getFont(); + } + } + + if (fFont != null) + fCanvas.setFont(fFont); + + updateNumberOfDigits(); + computeIndentations(); + return fCanvas; + } + + /** + * Disposes the column's resources. + */ + protected void handleDispose() { + + if (fCachedTextViewer != null) { + fCachedTextViewer.removeViewportListener(fInternalListener); + fCachedTextViewer.removeTextListener(fInternalListener); + fCachedTextViewer.getSelectionProvider().removeSelectionChangedListener(fInternalListener); + } + + if (fBuffer != null) { + fBuffer.dispose(); + fBuffer= null; + } + } + + /** + * Double buffer drawing. + * + * @param dest + * the gc to draw into + */ + private void doubleBufferPaint(GC dest) { + + Point size= fCanvas.getSize(); + + if (size.x <= 0 || size.y <= 0) + return; + + if (fBuffer != null) { + Rectangle r= fBuffer.getBounds(); + if (r.width != size.x || r.height != size.y) { + fBuffer.dispose(); + fBuffer= null; + } + } + if (fBuffer == null) + fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); + + GC gc= new GC(fBuffer); + gc.setFont(fCanvas.getFont()); + if (fForeground != null) + gc.setForeground(fForeground); + + try { + gc.setBackground(getBackground(fCanvas.getDisplay())); + gc.fillRectangle(0, 0, size.x, size.y); + + if (fCachedTextViewer instanceof ITextViewerExtension5) + doPaint1(gc); + else + doPaint(gc); + + } finally { + gc.dispose(); + } + + dest.drawImage(fBuffer, 0, 0); + } + + /** + * Returns the viewport height in lines. + * + * @return the viewport height in lines + */ + protected int getVisibleLinesInViewport() { + Rectangle clArea= fCachedTextWidget.getClientArea(); + return clArea.height / fCachedTextWidget.getLineHeight(); + } + + /** + * Draws the ruler column. + * + * @param gc + * the gc to draw into + */ + private void doPaint(GC gc) { + + if (fCachedTextViewer == null) + return; + + if (fCachedTextWidget == null) + return; + + int firstLine= 0; + + int topLine= fCachedTextWidget.getTopIndex(); + fScrollPos= fCachedTextWidget.getTopPixel(); + int lineheight= fCachedTextWidget.getLineHeight(); + int partialLineHidden= fScrollPos % lineheight; + + if (partialLineHidden > 0 && topLine > 0) // widgetTopLine shows the + // first fully visible line + --topLine; + + int bottomLine; + + try { + + IRegion region= fCachedTextViewer.getVisibleRegion(); + IDocument doc= fCachedTextViewer.getDocument(); + + if (doc == null) + return; + + firstLine= doc.getLineOfOffset(region.getOffset()); + if (firstLine > topLine) + topLine= firstLine; + + bottomLine= doc.getLineOfOffset(region.getOffset() + region.getLength()); + + } catch (BadLocationException x) { + return; + } + + fSensitiveToTextChanges= bottomLine - topLine < getVisibleLinesInViewport(); + + int baselineBias= getBaselineBias(gc); + + int topInset= fCachedTextViewer.getTopInset(); + int y= topInset - partialLineHidden; + Point canvasSize= fCanvas.getSize(); + Point selection= fCachedTextWidget.getSelection(); + boolean selectedLine= false; + Color defaultForeground= gc.getForeground(); + Color defaultBackground= gc.getBackground(); + + for (int line= topLine; y < canvasSize.y && line <= bottomLine; line++, y += lineheight) { + int widgetOffset= fCachedTextWidget.getOffsetAtLine(line); + if (fPaintSelectionBackground && widgetOffset >= selection.x && widgetOffset < selection.y) { + if (!selectedLine) { + selectedLine= true; + gc.setForeground(fCachedTextWidget.getSelectionForeground()); + gc.setBackground(fCachedTextWidget.getSelectionBackground()); + } + } else if (selectedLine) { + selectedLine= false; + gc.setForeground(defaultForeground); + gc.setBackground(defaultBackground); + } + if (selectedLine) { + gc.fillRectangle(0, y, canvasSize.x, lineheight); + } else if (fPaintStyleBackground && widgetOffset >= 0 && widgetOffset < fCachedTextWidget.getCharCount()) { + StyleRange style= fCachedTextWidget.getStyleRangeAtOffset(widgetOffset); + if (style != null && style.background != null) { + gc.setBackground(style.background); + gc.fillRectangle(0, y + baselineBias, canvasSize.x, lineheight - baselineBias); + gc.setBackground(defaultBackground); + } + } + paintLine(line, y, lineheight, gc, fCachedTextWidget.getDisplay()); + String s= createDisplayString(line); + int indentation= fAlignRight ? fIndentation[s.length()] : 0; + gc.drawString(s, indentation, y + baselineBias, true); + } + } + + /** + * Computes the string to be printed for line. The default + * implementation returns Integer.toString(line + 1). + * + * @param line + * the line number for which the string is generated + * @return the string to be printed on the ruler column for line + */ + String createDisplayString(int line) { + return Integer.toString(line + 1); + } + + /** + * Draws the ruler column. Uses ITextViewerExtension5 for the + * implementation. Will replace doPinat(GC). + * + * @param gc + * the gc to draw into + */ + private void doPaint1(GC gc) { + + if (fCachedTextViewer == null) + return; + + ITextViewerExtension5 extension= (ITextViewerExtension5) fCachedTextViewer; + + int widgetTopLine= fCachedTextWidget.getTopIndex(); + fScrollPos= fCachedTextWidget.getTopPixel(); + int lineheight= fCachedTextWidget.getLineHeight(); + int partialLineHidden= fScrollPos % lineheight; + + if (partialLineHidden > 0 && widgetTopLine > 0) // widgetTopLine shows + // the first fully + // visible line + --widgetTopLine; + + int modelTopLine= extension.widgetLine2ModelLine(widgetTopLine); + int modelBottomLine= fCachedTextViewer.getBottomIndex(); + if (modelBottomLine >= 0) + ++modelBottomLine; + + try { + + IRegion region= extension.getModelCoverage(); + IDocument doc= fCachedTextViewer.getDocument(); + + if (doc == null) + return; + + int coverageTopLine= doc.getLineOfOffset(region.getOffset()); + if (coverageTopLine > modelTopLine || modelTopLine == -1) + modelTopLine= coverageTopLine; + + int coverageBottomLine= doc.getLineOfOffset(region.getOffset() + region.getLength()); + if (coverageBottomLine < modelBottomLine || modelBottomLine == -1) + modelBottomLine= coverageBottomLine; + + } catch (BadLocationException x) { + return; + } + + fSensitiveToTextChanges= modelBottomLine - modelTopLine < getVisibleLinesInViewport(); + + int baselineBias= getBaselineBias(gc); + + int topInset= fCachedTextViewer.getTopInset(); + int y= topInset - partialLineHidden; + Point canvasSize= fCanvas.getSize(); + Point selection= fCachedTextWidget.getSelection(); + boolean selectedLine= false; + Color defaultForeground= gc.getForeground(); + Color defaultBackground= gc.getBackground(); + + for (int modelLine= modelTopLine; y < canvasSize.y && modelLine <= modelBottomLine; modelLine++) { + + // don't draw hidden (e.g. folded) lines + int widgetLine= extension.modelLine2WidgetLine(modelLine); + if (widgetLine == -1) + continue; + int widgetOffset= fCachedTextWidget.getOffsetAtLine(widgetLine); + if (fPaintSelectionBackground && widgetOffset >= selection.x && widgetOffset < selection.y) { + if (!selectedLine) { + selectedLine= true; + gc.setForeground(fCachedTextWidget.getSelectionForeground()); + gc.setBackground(fCachedTextWidget.getSelectionBackground()); + } + } else if (selectedLine) { + selectedLine= false; + gc.setForeground(defaultForeground); + gc.setBackground(defaultBackground); + } + if (selectedLine) { + gc.fillRectangle(0, y, canvasSize.x, lineheight); + } else if (fPaintStyleBackground && widgetOffset >= 0 && widgetOffset < fCachedTextWidget.getCharCount()) { + StyleRange style= fCachedTextWidget.getStyleRangeAtOffset(widgetOffset); + if (style != null && style.background != null) { + gc.setBackground(style.background); + gc.fillRectangle(0, y + baselineBias, canvasSize.x, lineheight - baselineBias); + gc.setBackground(defaultBackground); + } + } + + paintLine(modelLine, y, lineheight, gc, fCachedTextWidget.getDisplay()); + + String s= createDisplayString(modelLine); + int indentation= fAlignRight ? fIndentation[s.length()] : 0; + gc.drawString(s, indentation, y + baselineBias, true); + y += lineheight; + } + } + + /** + * Returns the difference between the baseline of the widget and the + * baseline as specified by the font for gc. When drawing + * text, the returned bias should be added to obtain text line up on + * the correct base line of the text widget. + * + * @param gc + * the GC to get the font metrics from + * @return the baseline bias to use when drawing text that is line up with + * fCachedTextWidget + */ + private int getBaselineBias(GC gc) { + /* + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=62951 widget line + * height may be more than the font height used for the text, + * since font styles (bold, italics...) can have larger font metrics + * than the simple font used for the numbers. + */ + int widgetBaseline= fCachedTextWidget.getBaseline(); + FontMetrics fm= gc.getFontMetrics(); + int fontBaseline= fm.getAscent() + fm.getLeading(); + Assert.isTrue(widgetBaseline >= fontBaseline); + int baselineBias= widgetBaseline - fontBaseline; + return baselineBias; + } + + /** + * Paints the line. After this method is called the text is painted + * on top of the result of this method. + *

+ * This default implementation does nothing. + *

+ * + * @param line + * the line of the document which the ruler is painted for + * @param y + * the y-coordinate of the box being painted for + * line, relative to gc + * @param lineheight + * the height of one line (and therefore of the box being + * painted) + * @param gc + * the drawing context the client may choose to draw on. + * @param display + * the display the drawing occurs on + */ + protected void paintLine(int line, int y, int lineheight, GC gc, Display display) { + } + + /** + * Triggers a redraw in the display thread. + */ + protected final void postRedraw() { + if (fCanvas != null && !fCanvas.isDisposed()) { + Display d= fCanvas.getDisplay(); + if (d != null) { + synchronized (fRunnableLock) { + if (fIsRunnablePosted) + return; + fIsRunnablePosted= true; + } + d.asyncExec(fRunnable); + } + } + } + + /* + * @see IVerticalRulerColumn#redraw() + */ + public void redraw() { + + if (fRelayoutRequired) { + layout(true); + return; + } + + if (fCanvas != null && !fCanvas.isDisposed()) { + GC gc= new GC(fCanvas); + doubleBufferPaint(gc); + gc.dispose(); + } + } + + /* + * @see IVerticalRulerColumn#setModel(IAnnotationModel) + */ + public void setModel(IAnnotationModel model) { + } + + /* + * @see IVerticalRulerColumn#setFont(Font) + */ + public void setFont(Font font) { + fFont= font; + if (fCanvas != null && !fCanvas.isDisposed()) { + fCanvas.setFont(fFont); + updateNumberOfDigits(); + computeIndentations(); + } + } + + /** + * Returns the parent (composite) ruler of this ruler column. + * + * @return the parent ruler + */ + protected CompositeRuler getParentRuler() { + return fParentRuler; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java new file mode 100644 index 00000000000..171ee7804e5 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.util.concurrent.ExecutionException; + +import org.eclipse.cdt.internal.ui.text.CWordFinder; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.AddressRangePosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyPosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.LabelPosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourcePosition; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextViewer; + +/** + * A text hover to evaluate registers and variables under the cursor. + */ +public class DisassemblyTextHover implements ITextHover { + + private final DisassemblyPart fDisassemblyPart; + + /** + * Create a new disassembly text hover. + */ + public DisassemblyTextHover(DisassemblyPart part) { + fDisassemblyPart= part; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + IDocument doc = textViewer.getDocument(); + return CWordFinder.findWord(doc, offset); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + DisassemblyDocument doc = (DisassemblyDocument)textViewer.getDocument(); + int offset = hoverRegion.getOffset(); + AddressRangePosition pos; + try { + String ident = doc.get(offset, hoverRegion.getLength()); + String value = null; + pos = doc.getModelPosition(offset); + if (pos instanceof SourcePosition) { + value = evaluateExpression(ident); + } else if (pos instanceof LabelPosition) { + value = evaluateExpression(ident); + } else if (pos instanceof DisassemblyPosition) { + // first, try to evaluate as register + value = evaluateRegister(ident); + if (value == null) { + // if this fails, try expression + value = evaluateExpression(ident); + } + } + if (value != null) { + return ident + " = " + value; //$NON-NLS-1$ + } + } catch (BadLocationException e) { + if (DsfDebugUIPlugin.getDefault().isDebugging()) { + DsfDebugUIPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, "Internal Error", e)); //$NON-NLS-1$ + } + } + return null; + } + + /** + * Evaluate the given register. + * @param register + * @return register value or null + */ + private String evaluateRegister(String register) { + // TLETODO [disassembly] evaluate register + return null; + } + + /** + * Evaluate the given expression. + * @param expr + * @return expression value or null + */ + private String evaluateExpression(String expr) { + final IExpressions expressions= fDisassemblyPart.getService(IExpressions.class); + if (expressions == null) { + return null; + } + final IFrameDMContext frameDmc= fDisassemblyPart.getTargetFrameContext(); + if (frameDmc == null || !fDisassemblyPart.isSuspended()) { + return null; + } + IExpressionDMContext exprDmc= expressions.createExpression(frameDmc, expr); + final FormattedValueDMContext valueDmc= expressions.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT); + final DsfExecutor executor= fDisassemblyPart.getSession().getExecutor(); + Query query= new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + expressions.getFormattedExpressionValue(valueDmc, new DataRequestMonitor(executor, rm) { + @Override + protected void handleSuccess() { + FormattedValueDMData data= getData(); + rm.setData(data); + rm.done(); + } + }); + }}; + + executor.execute(query); + FormattedValueDMData data= null; + try { + data= query.get(); + } catch (InterruptedException exc) { + } catch (ExecutionException exc) { + } + if (data != null) { + return data.getFormattedValue(); + } + return null; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyView.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyView.java new file mode 100644 index 00000000000..a85b6db47e1 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyView.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PartInitException; + +/** + * DisassemblyView + */ +public class DisassemblyView extends DisassemblyPart implements IViewPart { + + private ISelectionListener fDebugViewListener; + + /** + * + */ + public DisassemblyView() { + super(); + } + + /* + * @see com.windriver.ide.disassembly.views.DisassemblyPart#getActionBars() + */ + @Override + protected IActionBars getActionBars() { + return getViewSite().getActionBars(); + } + + /* + * @see org.eclipse.ui.IViewPart#getViewSite() + */ + public IViewSite getViewSite() { + return (IViewSite)getSite(); + } + + /* + * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite) + */ + public void init(IViewSite site) throws PartInitException { + setSite(site); + } + + /* + * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento) + */ + public void init(IViewSite site, IMemento memento) throws PartInitException { + setSite(site); + site.getPage().addSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, fDebugViewListener= new ISelectionListener() { + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + updateDebugContext(); + }}); + } + + /* + * @see org.eclipse.ui.IViewPart#saveState(org.eclipse.ui.IMemento) + */ + public void saveState(IMemento memento) { + } + + /* + * @see com.windriver.ide.disassembly.views.DisassemblyPart#contributeToActionBars() + */ + @Override + protected void contributeToActionBars(IActionBars bars) { + super.contributeToActionBars(bars); + fillLocalPullDown(bars.getMenuManager()); + } + + protected void fillLocalPullDown(IMenuManager manager) { + manager.add(fActionGotoPC); + manager.add(fActionGotoAddress); + manager.add(fActionToggleSource); + manager.add(new Separator()); + } + + /* + * @see com.windriver.ide.disassembly.views.DisassemblyPart#closePart() + */ + @Override + protected void closePart() { + getViewSite().getPage().hideView(this); + } + + /* + * @see com.windriver.ide.disassembly.views.DisassemblyPart#dispose() + */ + @Override + public void dispose() { + getSite().getPage().removeSelectionListener(fDebugViewListener); + super.dispose(); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java new file mode 100644 index 00000000000..467ae30c0f7 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.util.Iterator; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.source.CompositeRuler; +import org.eclipse.jface.text.source.IOverviewRuler; +import org.eclipse.jface.text.source.IVerticalRuler; +import org.eclipse.jface.text.source.IVerticalRulerColumn; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; + +/** + * DisassemblyViewer + */ +public class DisassemblyViewer extends SourceViewer { + + class ResizeListener implements ControlListener { + /* + * @see ControlListener#controlResized(ControlEvent) + */ + public void controlResized(ControlEvent e) { + updateViewportListeners(RESIZE); + } + /* + * @see ControlListener#controlMoved(ControlEvent) + */ + public void controlMoved(ControlEvent e) { + } + } + + private boolean fUserTriggeredScrolling; + private int fCachedLastTopPixel; + + // extra resize listener to workaround bug 171018 + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=171018 + private ResizeListener fResizeListener; + + /** + * Create a new DisassemblyViewer. + * @param parent + * @param ruler + * @param overviewRuler + * @param showsAnnotationOverview + * @param styles + */ + public DisassemblyViewer(Composite parent, IVerticalRuler ruler, IOverviewRuler overviewRuler, boolean showsAnnotationOverview, int styles) { + super(parent, ruler, overviewRuler, showsAnnotationOverview, styles); + // always readonly + setEditable(false); + } + + /* + * @see org.eclipse.jface.text.source.SourceViewer#createControl(org.eclipse.swt.widgets.Composite, int) + */ + @Override + protected void createControl(Composite parent, int styles) { + super.createControl(parent, styles); + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=171018 + getTextWidget().addControlListener(fResizeListener= new ResizeListener()); + } + + /* + * @see org.eclipse.jface.text.source.SourceViewer#handleDispose() + */ + @Override + protected void handleDispose() { + if (fResizeListener != null) { + getTextWidget().removeControlListener(fResizeListener); + } + super.handleDispose(); + } + + /* + * @see org.eclipse.jface.text.source.SourceViewer#doOperation(int) + */ + @Override + public void doOperation(int operation) { + switch (operation) { + case COPY: + StyledText textWidget = getTextWidget(); + if (textWidget == null || !redraws()) { + return; + } + if (textWidget.getSelectionCount() == 0) { + return; + } + String selectedText; + try { + selectedText = getSelectedText(); + } catch (BadLocationException e) { + // should not happend + DsfDebugUIPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, e.getLocalizedMessage(), e)); + return; + } + Clipboard clipboard = new Clipboard(textWidget.getDisplay()); + clipboard.setContents(new Object[] { selectedText }, new Transfer[] { TextTransfer.getInstance() }); + clipboard.dispose(); + break; + default: + super.doOperation(operation); + } + } + + /** + * Get the selected text together with text displayed in visible + * ruler columns. + * @return the selected text + * @throws BadLocationException + */ + public String getSelectedText() throws BadLocationException { + StringBuffer text = new StringBuffer(200); + String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$ + DisassemblyDocument doc = (DisassemblyDocument)getDocument(); + Point selection = getSelectedRange(); + int startOffset = selection.x; + int length = selection.y; + int endOffset = startOffset + length; + int startLine = doc.getLineOfOffset(startOffset); + int endLine = doc.getLineOfOffset(endOffset); + int firstLineOffset = startOffset - doc.getLineOffset(startLine); + if (firstLineOffset > 0) { + // partial first line + int lineLength = doc.getLineInformation(startLine).getLength(); + text.append(doc.get(startOffset, Math.min(lineLength - firstLineOffset, length))); + ++startLine; + if (startLine <= endLine) { + text.append(lineSeparator); + } + } + for (int line = startLine; line < endLine; ++line) { + String lineText = getLineText(line); + text.append(lineText); + text.append(lineSeparator); + } + if (doc.getLineOffset(endLine) < endOffset) { + // partial last line + if (startLine <= endLine) { + int lineStart = doc.getLineOffset(endLine); + text.append(getLinePrefix(endLine)); + text.append(doc.get(lineStart, endOffset - lineStart)); + } + } + return text.toString(); + } + + /** + * Return the content of the given line, excluding line separator. + * @param line the line number + * @return the line content + * @throws BadLocationException + */ + public String getLineText(int line) throws BadLocationException { + IDocument doc = getDocument(); + IRegion lineRegion = doc.getLineInformation(line); + return getLinePrefix(line) + doc.get(lineRegion.getOffset(), lineRegion.getLength()); + } + + /** + * Get the line prefix by concatenating the text displayed by + * the visible ruler columns. + * @param line the line number + * @return the prefix string with trailing blank or the empty string + */ + public String getLinePrefix(int line) { + StringBuffer prefix = new StringBuffer(10); + IVerticalRuler ruler = getVerticalRuler(); + if (ruler instanceof CompositeRuler) { + for (Iterator iter = ((CompositeRuler)ruler).getDecoratorIterator(); iter.hasNext();) { + IVerticalRulerColumn column = (IVerticalRulerColumn) iter.next(); + if (column instanceof DisassemblyRulerColumn) { + DisassemblyRulerColumn disassColumn = (DisassemblyRulerColumn)column; + String columnText = disassColumn.createDisplayString(line); + prefix.append(columnText); + int columnWidth = disassColumn.computeNumberOfCharacters(); + columnWidth -= columnText.length(); + while(columnWidth-- > 0) + prefix.append(' '); + prefix.append(' '); + } + } + } + return prefix.toString(); + } + + /** + * Scroll the given position into the visible area if it is not yet visible. + * @param offset + * @see org.eclipse.jface.text.TextViewer#revealRange(int, int) + */ + public void revealOffset(int offset, boolean onTop) { + try { + IDocument doc = getVisibleDocument(); + + int focusLine = doc.getLineOfOffset(offset); + + StyledText textWidget = getTextWidget(); + int top = textWidget.getTopIndex(); + if (top > -1) { + + // scroll vertically + int lines = getEstimatedVisibleLinesInViewport(); + int bottom = top + lines; + + int bottomBuffer = Math.max(1, lines / 3); + + if (!onTop && focusLine >= top && focusLine <= bottom - bottomBuffer) { + // do not scroll at all as it is already visible + } else { + if (focusLine > bottom - bottomBuffer && focusLine <= bottom) { + // focusLine is already in bottom bufferZone + // scroll to top of bottom bufferzone - for smooth down-scrolling + int scrollDelta = focusLine - (bottom - bottomBuffer); + textWidget.setTopIndex(top + scrollDelta); + } else { + // scroll to top of visible area minus buffer zone + int topBuffer = onTop ? 0 : lines / 3; + textWidget.setTopIndex(Math.max(0, focusLine - topBuffer)); + } + updateViewportListeners(INTERNAL); + } + } + } catch (BadLocationException ble) { + throw new IllegalArgumentException(ble.getLocalizedMessage()); + } + } + + /** + * @return the number of visible lines in the viewport assuming a constant + * line height. + */ + private int getEstimatedVisibleLinesInViewport() { + StyledText textWidget = getTextWidget(); + if (textWidget != null) { + Rectangle clArea= textWidget.getClientArea(); + if (!clArea.isEmpty()) + return clArea.height / textWidget.getLineHeight(); + } + return -1; + } + + int getLastTopPixel() { + return fCachedLastTopPixel; + } + boolean isUserTriggeredScrolling() { + return fUserTriggeredScrolling; + } + + /* + * @see org.eclipse.jface.text.TextViewer#updateViewportListeners(int) + */ + @Override + protected void updateViewportListeners(int origin) { + fCachedLastTopPixel = fLastTopPixel; + fUserTriggeredScrolling = origin != INTERNAL && origin != RESIZE; + super.updateViewportListeners(origin); + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java new file mode 100644 index 00000000000..9092894f209 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.IUndoManager; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; +import org.eclipse.jface.text.presentation.IPresentationDamager; +import org.eclipse.jface.text.presentation.IPresentationReconciler; +import org.eclipse.jface.text.presentation.IPresentationRepairer; +import org.eclipse.jface.text.presentation.PresentationReconciler; +import org.eclipse.jface.text.reconciler.IReconciler; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.editors.text.TextSourceViewerConfiguration; + +/** + * DisassemblyViewerConfiguration + */ +public class DisassemblyViewerConfiguration extends TextSourceViewerConfiguration { + + private DisassemblyPart fPart; + + /** + * SimpleDamagerRepairer + */ + public class SimpleDamagerRepairer implements IPresentationDamager, IPresentationRepairer { + + /* + * @see org.eclipse.jface.text.presentation.IPresentationDamager#setDocument(org.eclipse.jface.text.IDocument) + */ + public void setDocument(IDocument document) { + } + + /* + * @see org.eclipse.jface.text.presentation.IPresentationDamager#getDamageRegion(org.eclipse.jface.text.ITypedRegion, org.eclipse.jface.text.DocumentEvent, boolean) + */ + public IRegion getDamageRegion(ITypedRegion partition, DocumentEvent e, boolean documentPartitioningChanged) { + int start= e.fOffset; + int end= e.getOffset() + (e.getText() == null ? 0 : e.getText().length()); + return new Region(start, end - start); + } + + /* + * @see org.eclipse.jface.text.presentation.IPresentationRepairer#createPresentation(org.eclipse.jface.text.TextPresentation, org.eclipse.jface.text.ITypedRegion) + */ + public void createPresentation(TextPresentation presentation, ITypedRegion damage) { + // do nothing + } + + } + + /** + * + */ + public DisassemblyViewerConfiguration(DisassemblyPart part) { + super(EditorsUI.getPreferenceStore()); + fPart = part; + } + + /* + * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getPresentationReconciler(org.eclipse.jface.text.source.ISourceViewer) + */ + @Override + public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) { + PresentationReconciler reconciler = new PresentationReconciler(); + SimpleDamagerRepairer dr = new SimpleDamagerRepairer(); + reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); + reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); + return reconciler; + } + /* + * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getUndoManager(org.eclipse.jface.text.source.ISourceViewer) + */ + @Override + public IUndoManager getUndoManager(ISourceViewer sourceViewer) { + // no undo/redo + return null; + } + + /* + * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getTextHover(org.eclipse.jface.text.source.ISourceViewer, java.lang.String) + */ + @Override + public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { + return new DisassemblyTextHover(fPart); + } + + /* + * @see org.eclipse.ui.editors.text.TextSourceViewerConfiguration#getHyperlinkDetectors(org.eclipse.jface.text.source.ISourceViewer) + */ + @Override + public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) { + IHyperlinkDetector[] inheritedDetectors= super.getHyperlinkDetectors(sourceViewer); + + if (fPart == null) + return inheritedDetectors; + + int inheritedDetectorsLength= inheritedDetectors != null ? inheritedDetectors.length : 0; + IHyperlinkDetector[] detectors= new IHyperlinkDetector[inheritedDetectorsLength + 1]; + detectors[0]= new DisassemblyHyperlinkDetector(fPart); + for (int i= 0; i < inheritedDetectorsLength; i++) { + detectors[i+1]= inheritedDetectors[i]; + } + + return detectors; + } + + /* + * @see org.eclipse.ui.editors.text.TextSourceViewerConfiguration#getReconciler(org.eclipse.jface.text.source.ISourceViewer) + */ + @Override + public IReconciler getReconciler(ISourceViewer sourceViewer) { + // disable spell checking + return null; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/EditionFinderJob.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/EditionFinderJob.java new file mode 100644 index 00000000000..1d3241481eb --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/EditionFinderJob.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.math.BigInteger; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFileState; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourceFileInfo; + +/** + * A job to find a suitable edition from the local history + * based on a file and the timestamp of the code module. + */ +class EditionFinderJob extends Job { + + private final IFile fFile; + private final BigInteger fAddress; + private final DisassemblyPart fDisassemblyPart; + private final SourceFileInfo fSourceInfo; + + /** + * Create a new edition finder for a file resource and address. + * + * @param sourceInfo the file info containing the file resource for which to find an edition + * @param address address inside the module + * @param disassemblyPart the disassembly part where this job originated from + */ + public EditionFinderJob(SourceFileInfo sourceInfo, BigInteger address, DisassemblyPart disassemblyPart) { + super(DisassemblyMessages.EditionFinderJob_name); + Assert.isNotNull(sourceInfo); + Assert.isLegal(sourceInfo.fFile instanceof IFile); + fSourceInfo= sourceInfo; + fFile = (IFile)sourceInfo.fFile; + fAddress = address; + fDisassemblyPart= disassemblyPart; + setRule(fFile); + setSystem(true); + sourceInfo.fEditionJob= this; + } + + /* + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected IStatus run(IProgressMonitor monitor) { + monitor.beginTask(DisassemblyMessages.EditionFinderJob_name, 2); + monitor.subTask(DisassemblyMessages.EditionFinderJob_task_get_timestamp); + long moduleTime; + Object token = fDisassemblyPart.retrieveModuleTimestamp(fAddress); + if (token != null && !(token instanceof Long) && !monitor.isCanceled()) { + try { + synchronized (token) { + token.wait(1000); + } + } catch (InterruptedException e) { + DisassemblyPart.internalError(e); + } + token = fDisassemblyPart.retrieveModuleTimestamp(fAddress); + } + monitor.worked(1); + if (token instanceof Long && !monitor.isCanceled()) { + moduleTime = ((Long)token).longValue(); + long buildTime = moduleTime * 1000; + if (fFile.getLocalTimeStamp() > buildTime) { + monitor.subTask(DisassemblyMessages.EditionFinderJob_task_search_history); + // get history - recent states first + IFileState[] states; + try { + states = fFile.getHistory(new SubProgressMonitor(monitor, 1)); + } catch (CoreException e) { + states = new IFileState[0]; + } + for (int i = 0; i < states.length; i++) { + IFileState state = states[i]; + long saveTime = state.getModificationTime(); + if (saveTime <= buildTime) { + fSourceInfo.fEdition = state; + break; + } + } + } + } + fSourceInfo.fEditionJob = null; + monitor.worked(1); + monitor.done(); + return Status.OK_STATUS; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java new file mode 100644 index 00000000000..0cc653eba03 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.AddressRangePosition; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyPosition; +import org.eclipse.jface.text.BadLocationException; + +/** + * A vertical ruler column to display the function + offset of instructions. + */ +public class FunctionOffsetRulerColumn extends DisassemblyRulerColumn { + + /** + * Default constructor. + */ + public FunctionOffsetRulerColumn() { + super(); + } + + /* + * @see org.eclipse.jface.text.source.LineNumberRulerColumn#createDisplayString(int) + */ + @Override + protected String createDisplayString(int line) { + DisassemblyDocument doc = (DisassemblyDocument)getParentRuler().getTextViewer().getDocument(); + int offset; + try { + offset = doc.getLineOffset(line); + AddressRangePosition pos = doc.getDisassemblyPosition(offset); + if (pos instanceof DisassemblyPosition && pos.length > 0 && pos.offset == offset && pos.fValid) { + DisassemblyPosition disassPos = (DisassemblyPosition)pos; + return new String(disassPos.fFunction); + } else if (pos != null && !pos.fValid) { + return DOTS.substring(0, doc.getMaxFunctionLength()); + } + } catch (BadLocationException e) { + // silently ignored + } + return ""; //$NON-NLS-1$ + } + + /* + * @see com.windriver.ide.disassembly.views.DisassemblyRulerColumn#computeNumberOfCharacters() + */ + @Override + protected int computeNumberOfCharacters() { + DisassemblyDocument doc = (DisassemblyDocument)getParentRuler().getTextViewer().getDocument(); + return doc.getMaxFunctionLength(); + } + + /* + * @see org.eclipse.jface.text.source.IVerticalRulerColumn#getWidth() + */ + @Override + public int getWidth() { + return super.getWidth(); + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java new file mode 100644 index 00000000000..72d3754577d --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; + +/** + * IDisassemblyHelpContextIds + */ +public interface IDisassemblyHelpContextIds { + + public final static String PREFIX = DsfDebugUIPlugin.PLUGIN_ID + '.'; + public final static String DISASSEMBLY_PREFERENCE_PAGE = PREFIX + "disassembly_preference_page"; //$NON-NLS-1$ + public final static String DISASSEMBLY_VIEW = PREFIX + "disassembly_view"; //$NON-NLS-1$ + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java new file mode 100644 index 00000000000..392de20c3c3 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import java.math.BigInteger; + +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.ui.IWorkbenchPart; + +/** + * Interface which the disassembly view and editor implement. + */ +public interface IDisassemblyPart extends IWorkbenchPart { + + /** + * Property id for the active state of the part. + */ + public final int PROP_ACTIVE= 0x505; + + /** + * Property id for the connected state of the part. + */ + public final int PROP_CONNECTED= 0x506; + + /** + * Property id for the suspended state of the underlying execution context. + */ + public final int PROP_SUSPENDED= 0x507; + + /** + * Test whether this part is connected to a debug session and execution context. + * + * @return true if the part is connected to a debug session and execution context + */ + boolean isConnected(); + + /** + * Test whether this part is active. A part is active if it is visible and connected. + * + * @return true if the part is active + */ + boolean isActive(); + + /** + * Test whether the underlying execution context is currently suspended. + * Implies connected state. + * + * @return true if the execution context is currently suspended + */ + boolean isSuspended(); + + /** + * Get access to the text viewer. + * + * @return the text viewer + */ + ISourceViewer getTextViewer(); + + /** + * Navigate to the given address. + * + * @param address + */ + void gotoAddress(BigInteger address); + + /** + * Navigate to current program counter. + */ + void gotoProgramCounter(); + + /** + * Navigate to the address the given expression evaluates to. + * + * @param expression a symbolic address expression + */ + void gotoSymbol(String expression); + + /** + * Adds a ruler context menu listener to the disassembly part. + * + * @param listener the listener + */ + void addRulerContextMenuListener(IMenuListener listener); + + /** + * Removes a ruler context menu listener from the disassembly part. + * + * @param listener the listener + */ + void removeRulerContextMenuListener(IMenuListener listener); + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/SourceColorerJob.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/SourceColorerJob.java new file mode 100644 index 00000000000..6a8b339184e --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/SourceColorerJob.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly; + +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.model.SourceFileInfo; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.progress.IWorkbenchSiteProgressService; +import org.eclipse.ui.progress.UIJob; + +/** + * UI job to color source code. + */ +class SourceColorerJob extends UIJob implements Runnable { + + private final DisassemblyPart fDisassemblyPart; + private final ISourceViewer fViewer; + private final DisassemblyDocument fDocument; + private final IStorage fStorage; + + public SourceColorerJob(Display jobDisplay, IStorage storage, DisassemblyPart disassemblyPart) { + super(DisassemblyMessages.SourceColorerJob_name); + fDisassemblyPart= disassemblyPart; + fViewer= disassemblyPart.getTextViewer(); + fDocument= (DisassemblyDocument) fViewer.getDocument(); + fStorage = storage; + setDisplay(fDisassemblyPart.getSite().getShell().getDisplay()); + setSystem(true); + setPriority(INTERACTIVE); + } + + /* + * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + if (fViewer != null && !monitor.isCanceled()) { + monitor.beginTask(DisassemblyMessages.SourceColorerJob_name, IProgressMonitor.UNKNOWN); + SourceFileInfo fi = fDocument.getSourceInfo(fStorage); + if (fi != null) { + fi.initPresentationCreator(fViewer); + if (fi.fError != null) { + String message= DisassemblyMessages.Disassembly_log_error_readFile + fi.fFileKey; + fDisassemblyPart.logWarning(message, fi.fError); + } + } + fDisassemblyPart.updateInvalidSource(); + monitor.done(); + } + return Status.OK_STATUS; + } + + /* + * @see java.lang.Runnable#run() + */ + public void run() { + IWorkbenchSiteProgressService progressService = (IWorkbenchSiteProgressService)fDisassemblyPart.getSite().getAdapter(IWorkbenchSiteProgressService.class); + if(progressService != null) { + progressService.schedule(this, 0, true); + } else { + schedule(); + } + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java new file mode 100644 index 00000000000..7ce85f57210 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.jface.action.Action; +import org.eclipse.ui.IPropertyListener; +import org.eclipse.ui.texteditor.IUpdate; + +public abstract class AbstractDisassemblyAction extends Action implements IUpdate, IPropertyListener { + + protected IDisassemblyPart fDisassemblyPart; + + AbstractDisassemblyAction() { + } + + /** + * Create a disassembly action. + * + * @param disassemblyPart + */ + public AbstractDisassemblyAction(IDisassemblyPart disassemblyPart) { + Assert.isLegal(disassemblyPart != null); + fDisassemblyPart= disassemblyPart; + fDisassemblyPart.addPropertyListener(this); + } + + /** + * @return the disassembly part + */ + public final IDisassemblyPart getDisassemblyPart() { + return fDisassemblyPart; + } + + /* + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public abstract void run(); + + public void update() { + boolean enabled= fDisassemblyPart == null || fDisassemblyPart.isConnected(); + setEnabled(enabled); + } + + /* + * @see org.eclipse.ui.IPropertyListener#propertyChanged(java.lang.Object, int) + */ + public void propertyChanged(Object source, int propId) { + if (source == fDisassemblyPart && (propId & 0x500) != 0) { + update(); + } + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java new file mode 100644 index 00000000000..118abcc286e --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import java.util.Iterator; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IVerticalRulerInfo; +import org.eclipse.ui.texteditor.SimpleMarkerAnnotation; + +/** + * Abstract implementation of a breakpoint ruler action. + */ +public abstract class AbstractDisassemblyBreakpointRulerAction extends AbstractDisassemblyRulerAction { + + /** + * Create breakpoint ruler action. + * + * @param disassemblyPart + * @param rulerInfo + */ + protected AbstractDisassemblyBreakpointRulerAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) { + super(disassemblyPart, rulerInfo); + } + + /** + * Returns the breakpoint at the last line of mouse activity in the ruler + * or null if none. + * + * @return breakpoint associated with activity in the ruler or null + */ + protected IBreakpoint getBreakpoint() { + IAnnotationModel annotationModel = getAnnotationModel(); + IDocument document = getDocument(); + if (annotationModel != null) { + Iterator iterator = annotationModel.getAnnotationIterator(); + while (iterator.hasNext()) { + Object object = iterator.next(); + if (object instanceof SimpleMarkerAnnotation) { + SimpleMarkerAnnotation markerAnnotation = (SimpleMarkerAnnotation) object; + IMarker marker = markerAnnotation.getMarker(); + try { + if (marker.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) { + Position position = annotationModel.getPosition(markerAnnotation); + int line = document.getLineOfOffset(position.getOffset()); + if (line == getRulerInfo().getLineOfLastMouseButtonActivity()) { + IBreakpoint breakpoint = DebugPlugin.getDefault().getBreakpointManager().getBreakpoint(marker); + if (breakpoint != null) { + return breakpoint; + } + } + } + } catch (CoreException e) { + } catch (BadLocationException e) { + } + } + } + } + return null; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java new file mode 100644 index 00000000000..248801fba39 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IVerticalRulerInfo; + +/** + * Abstract implementation for disassembly vertical ruler actions. + */ +public abstract class AbstractDisassemblyRulerAction extends AbstractDisassemblyAction { + + private final IVerticalRulerInfo fRulerInfo; + + protected AbstractDisassemblyRulerAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) { + fDisassemblyPart= disassemblyPart; + fRulerInfo= rulerInfo; + } + + public final IVerticalRulerInfo getRulerInfo() { + return fRulerInfo; + } + + public final IDocument getDocument() { + return getDisassemblyPart().getTextViewer().getDocument(); + } + + public final IAnnotationModel getAnnotationModel() { + return getDisassemblyPart().getTextViewer().getAnnotationModel(); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java new file mode 100644 index 00000000000..eda11b1d47d --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.text.source.IVerticalRulerInfo; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IViewActionDelegate; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.actions.ActionDelegate; +import org.eclipse.ui.texteditor.IUpdate; + +/** + * This class serves as an adapter for actions contributed to the vertical ruler's + * context menu. This adapter provides the contributed actions access to their disassembly part + * and the disassembly part's vertical ruler. These actions gain only limited access to the vertical + * ruler as defined by IVerticalRulerInfo. The adapter updates the + * adapter (inner) action on menu and mouse action on the vertical ruler.

+ * Extending classes must implement the factory method + * createAction(IDisassemblyPart, IVerticalRulerInfo). + * + * @see org.eclipse.ui.texteditor.AbstractRulerActionDelegate + */ +public abstract class AbstractDisassemblyRulerActionDelegate extends ActionDelegate implements IEditorActionDelegate, IViewActionDelegate, MouseListener, IMenuListener { + + /** The disassembly part. */ + private IDisassemblyPart fDisassemblyPart; + /** The action calling the action delegate. */ + private IAction fCallerAction; + /** The underlying action. */ + private IAction fAction; + + /** + * The factory method creating the underlying action. + * + * @param disassemblyPart the disassembly part the action to be created will work on + * @param rulerInfo the vertical ruler the action to be created will work on + * @return the created action + */ + protected abstract IAction createAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo); + + /* + * @see IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, org.eclipse.ui.IEditorPart) + */ + public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) { + setTargetPart(callerAction, targetEditor); + } + + /* + * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart) + */ + public void init(IViewPart view) { + setTargetPart(fCallerAction, view); + } + + @Override + public void init(IAction action) { + fCallerAction= action; + } + + private void setTargetPart(IAction callerAction, IWorkbenchPart targetPart) { + if (fDisassemblyPart != null) { + IVerticalRulerInfo rulerInfo= (IVerticalRulerInfo) fDisassemblyPart.getAdapter(IVerticalRulerInfo.class); + if (rulerInfo != null) { + Control control= rulerInfo.getControl(); + if (control != null && !control.isDisposed()) + control.removeMouseListener(this); + } + + fDisassemblyPart.removeRulerContextMenuListener(this); + } + + fDisassemblyPart= (IDisassemblyPart)(targetPart == null ? null : targetPart.getAdapter(IDisassemblyPart.class)); + fCallerAction= callerAction; + fAction= null; + + if (fDisassemblyPart != null) { + fDisassemblyPart.addRulerContextMenuListener(this); + + IVerticalRulerInfo rulerInfo= (IVerticalRulerInfo) fDisassemblyPart.getAdapter(IVerticalRulerInfo.class); + if (rulerInfo != null) { + fAction= createAction(fDisassemblyPart, rulerInfo); + update(); + + Control control= rulerInfo.getControl(); + if (control != null && !control.isDisposed()) + control.addMouseListener(this); + } + } + } + + @Override + public void run(IAction callerAction) { + if (fAction != null) + fAction.run(); + } + + @Override + public void runWithEvent(IAction action, Event event) { + if (fAction != null) + fAction.runWithEvent(event); + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + /* + * This is a ruler action - don't update on selection. + */ + } + + /** + * Updates to the current state. + */ + private void update() { + if (fAction instanceof IUpdate) { + ((IUpdate) fAction).update(); + if (fCallerAction != null) { + fCallerAction.setText(fAction.getText()); + fCallerAction.setEnabled(fAction.isEnabled()); + } + } + } + + /* + * @see IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager) + */ + public void menuAboutToShow(IMenuManager manager) { + update(); + } + + /* + * @see MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDoubleClick(MouseEvent e) { + } + + /* + * @see MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDown(MouseEvent e) { + update(); + } + + /* + * @see MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) + */ + public void mouseUp(MouseEvent e) { + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java new file mode 100644 index 00000000000..99c9525dd7b --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import java.math.BigInteger; + +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyPart; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.swt.widgets.Shell; + +public final class ActionGotoAddress extends AbstractDisassemblyAction { + public ActionGotoAddress(IDisassemblyPart disassemblyPart) { + super(disassemblyPart); + setText(DisassemblyMessages.Disassembly_action_GotoAddress_label); + } + @Override + public void run() { + IInputValidator validator = new IInputValidator() { + public String isValid(String input) { + if (input == null || input.length() == 0) + return " "; //$NON-NLS-1$ + try { + BigInteger address= DisassemblyPart.decodeAddress(input); + if (address.compareTo(BigInteger.ZERO) < 0) { + return DisassemblyMessages.Disassembly_GotoAddressDialog_error_invalid_address; + } + } catch (NumberFormatException x) { + return DisassemblyMessages.Disassembly_GotoAddressDialog_error_not_a_number; //; + } + return null; + } + }; + String defaultValue = ((ITextSelection)getDisassemblyPart().getSite().getSelectionProvider().getSelection()).getText(); + if (validator.isValid(defaultValue) != null) { + defaultValue = DsfDebugUIPlugin.getDefault().getDialogSettings().get("gotoAddress"); //$NON-NLS-1$ + if (validator.isValid(defaultValue) != null) { + defaultValue = ""; //$NON-NLS-1$ + } + } + String dlgTitle = DisassemblyMessages.Disassembly_GotoAddressDialog_title; + String dlgLabel = DisassemblyMessages.Disassembly_GotoAddressDialog_label; + final Shell shell= getDisassemblyPart().getSite().getShell(); + InputDialog dlg = new InputDialog(shell, dlgTitle, dlgLabel, defaultValue, validator); + if (dlg.open() == IDialogConstants.OK_ID) { + String value = dlg.getValue(); + BigInteger address= DisassemblyPart.decodeAddress(value); + DsfDebugUIPlugin.getDefault().getDialogSettings().put("gotoAddress", value); //$NON-NLS-1$ + getDisassemblyPart().gotoAddress(address); + } + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java new file mode 100644 index 00000000000..d5729b29f76 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; + +public final class ActionGotoProgramCounter extends AbstractDisassemblyAction { + public ActionGotoProgramCounter(IDisassemblyPart disassemblyPart) { + super(disassemblyPart); + setText(DisassemblyMessages.Disassembly_action_GotoPC_label); + setToolTipText(DisassemblyMessages.Disassembly_action_GotoPC_tooltip); + } + @Override + public void run() { + getDisassemblyPart().gotoProgramCounter(); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java new file mode 100644 index 00000000000..4849a8bd5d3 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.cdt.internal.ui.text.CWordFinder; +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.swt.widgets.Shell; + +public final class ActionGotoSymbol extends AbstractDisassemblyAction { + public ActionGotoSymbol(IDisassemblyPart disassemblyPart) { + super(disassemblyPart); + setText(DisassemblyMessages.Disassembly_action_GotoSymbol_label); + } + @Override + public void run() { + ITextViewer viewer = getDisassemblyPart().getTextViewer(); + IDocument document= viewer.getDocument(); + IRegion wordRegion = CWordFinder.findWord(document, viewer.getSelectedRange().x); + String defaultValue = null; + if (wordRegion != null) { + try { + defaultValue = document.get(wordRegion.getOffset(), wordRegion.getLength()); + } catch (BadLocationException e) { + // safely ignored + } + } + if (defaultValue == null) { + defaultValue = DsfDebugUIPlugin.getDefault().getDialogSettings().get("gotoSymbol"); //$NON-NLS-1$ + if (defaultValue == null) { + defaultValue = ""; //$NON-NLS-1$ + } + } + String dlgTitle = DisassemblyMessages.Disassembly_GotoSymbolDialog_title; + String dlgLabel = DisassemblyMessages.Disassembly_GotoSymbolDialog_label; + final Shell shell= getDisassemblyPart().getSite().getShell(); + InputDialog dlg = new InputDialog(shell, dlgTitle, dlgLabel, defaultValue, null); + if (dlg.open() == IDialogConstants.OK_ID) { + String value = dlg.getValue(); + DsfDebugUIPlugin.getDefault().getDialogSettings().put("gotoSymbol", value); //$NON-NLS-1$ + getDisassemblyPart().gotoSymbol(value); + } + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java new file mode 100644 index 00000000000..7be4676c79f --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages; +import org.eclipse.jface.action.Action; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.dialogs.PreferencesUtil; + +public final class ActionOpenPreferences extends Action { + private final static String PREF_PAGE_ID = "org.eclipse.dd.dsf.debug.ui.disassembly.preferencePage"; //$NON-NLS-1$ + private final Shell fShell; + public ActionOpenPreferences(Shell shell) { + fShell= shell; + setText(DisassemblyMessages.Disassembly_action_OpenPreferences_label); + } + @Override + public void run() { + PreferencesUtil.createPreferenceDialogOn(fShell, PREF_PAGE_ID, new String[] { PREF_PAGE_ID }, null).open(); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java new file mode 100644 index 00000000000..17aa90acbb9 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.cdt.debug.core.model.ICBreakpoint; +import org.eclipse.cdt.debug.internal.ui.CBreakpointContext; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.jface.text.source.IVerticalRulerInfo; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.ui.dialogs.PropertyDialogAction; + +/** + * Ruler action to display breakpoint properties. + */ +public class BreakpointPropertiesRulerAction extends AbstractDisassemblyBreakpointRulerAction { + + private Object fContext; + + protected BreakpointPropertiesRulerAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) { + super(disassemblyPart, rulerInfo); + setText(DisassemblyMessages.Disassembly_action_BreakpointProperties_label); + } + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.AbstractDisassemblyAction#run() + */ + @Override + public void run() { + if ( fContext != null ) { + PropertyDialogAction action = new PropertyDialogAction( getDisassemblyPart().getSite(), new ISelectionProvider() { + + public void addSelectionChangedListener( ISelectionChangedListener listener ) { + } + + public ISelection getSelection() { + return new StructuredSelection( fContext ); + } + + public void removeSelectionChangedListener( ISelectionChangedListener listener ) { + } + + public void setSelection( ISelection selection ) { + } + } ); + action.run(); + action.dispose(); + } + } + + /* + * @see IUpdate#update() + */ + @Override + public void update() { + IBreakpoint breakpoint= getBreakpoint(); + if (breakpoint instanceof ICBreakpoint) { + fContext = new CBreakpointContext((ICBreakpoint)breakpoint, getDebugContext()); + } else { + fContext = breakpoint; + } + setEnabled( fContext != null ); + } + + private ISelection getDebugContext() { + return DebugUITools.getDebugContextManager().getContextService(getDisassemblyPart().getSite().getWorkbenchWindow()).getActiveContext(); + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java new file mode 100644 index 00000000000..c34f3b78ea9 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.source.IVerticalRulerInfo; + +/** + * Ruler action delegate for the breakpoint properties action. + */ +public class BreakpointPropertiesRulerActionDelegate extends AbstractDisassemblyRulerActionDelegate { + + /* + * @see org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions.AbstractDisassemblyRulerActionDelegate#createAction(org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyPart, org.eclipse.jface.text.source.IVerticalRulerInfo) + */ + @Override + protected IAction createAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) { + return new BreakpointPropertiesRulerAction(disassemblyPart, rulerInfo); + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java new file mode 100644 index 00000000000..765d96027d6 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.ui.texteditor.IUpdate; + +/** + * TextOperationAction + */ +public class TextOperationAction extends Action implements IUpdate { + + private int fOperationCode= -1; + private ITextOperationTarget fOperationTarget; + + public TextOperationAction(ITextViewer viewer, int operationCode) { + fOperationCode= operationCode; + fOperationTarget= viewer.getTextOperationTarget(); + update(); + } + + /** + * Updates the enabled state of the action. + * Fires a property change if the enabled state changes. + * + * @see Action#firePropertyChange(String, Object, Object) + */ + public void update() { + + boolean wasEnabled= isEnabled(); + boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode)); + setEnabled(isEnabled); + + if (wasEnabled != isEnabled) { + firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE, isEnabled ? Boolean.TRUE : Boolean.FALSE); + } + } + + /** + * @see Action#run() + */ + @Override + public void run() { + if (fOperationCode != -1 && fOperationTarget != null) { + fOperationTarget.doOperation(fOperationCode); + } + } + } diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/Addr2Line.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/Addr2Line.java new file mode 100644 index 00000000000..0e171abb8a2 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/Addr2Line.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + + +public class Addr2Line { + public BigInteger addr; + public Addr2Line next; + public int first; + public int last; + + public static int hash(BigInteger addr, int size) { + return (int)((addr.shiftRight(2).longValue()) % size); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java new file mode 100644 index 00000000000..4740a8f7335 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + +import org.eclipse.jface.text.Position; + +/** + * AddressRangePosition + */ +public class AddressRangePosition extends Position { + + public BigInteger fAddressOffset; + public BigInteger fAddressLength; + public boolean fValid; + + /** + * @param offset + * @param length + */ + public AddressRangePosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength) { + super(offset, length); + fAddressOffset = addressOffset; + fAddressLength = addressLength; + fValid = true; + } + + /** + * @param offset + * @param length + * @param valid + */ + public AddressRangePosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, boolean valid) { + super(offset, length); + fAddressOffset = addressOffset; + fAddressLength = addressLength; + fValid = valid; + } + + /** + * @param address + * @return + */ + public boolean containsAddress(BigInteger address) { + return address.compareTo(fAddressOffset) >= 0 + && address.compareTo(fAddressOffset.add(fAddressLength)) < 0; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object other) { + // identity comparison + return this == other; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java new file mode 100644 index 00000000000..ff9c7ba36cf --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; +import java.util.Iterator; + +import org.eclipse.cdt.debug.core.model.ICAddressBreakpoint; +import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointListener; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.ILineBreakpoint; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentListener; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationModel; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.texteditor.MarkerAnnotation; +import org.eclipse.ui.texteditor.SimpleMarkerAnnotation; + +/** + * Annotation model for breakpoints in the disassembly. + * Works only with {@link DisassemblyDocument}. + */ +public class BreakpointsAnnotationModel extends AnnotationModel implements IBreakpointListener, IDocumentListener { + + private Runnable fCatchup; + + @Override + public void connect(IDocument document) { + super.connect(document); + if (document instanceof DisassemblyDocument) { + final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager(); + addBreakpoints(bpMgr.getBreakpoints()); + bpMgr.addBreakpointListener(this); + document.addDocumentListener(this); + } + } + + @Override + public void disconnect(IDocument document) { + if (document instanceof DisassemblyDocument) { + final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager(); + bpMgr.removeBreakpointListener(this); + document.removeDocumentListener(this); + fCatchup= null; + } + super.disconnect(document); + } + + private void catchupWithBreakpoints() { + removeAllAnnotations(false); + final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager(); + addBreakpoints(bpMgr.getBreakpoints()); + } + + private void addBreakpoints(IBreakpoint[] breakpoints) { + for (IBreakpoint breakpoint : breakpoints) { + addBreakpointAnnotation(breakpoint, false); + } + fireModelChanged(); + } + + /* + * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) + */ + public void breakpointAdded(IBreakpoint breakpoint) { + addBreakpointAnnotation(breakpoint, true); + } + + /* + * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { + Annotation a= findAnnotation(breakpoint.getMarker()); + if (a != null) { + if (a instanceof SimpleMarkerAnnotation) { + ((SimpleMarkerAnnotation)a).update(); + } + synchronized (getLockObject()) { + getAnnotationModelEvent().annotationChanged(a); + } + fireModelChanged(); + } + } + + /* + * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { + Annotation a= findAnnotation(breakpoint.getMarker()); + if (a != null) { + removeAnnotation(a, true); + } + } + + @SuppressWarnings("unchecked") + private Annotation findAnnotation(IMarker marker) { + for (Iterator it= getAnnotationIterator(false); it.hasNext();) { + SimpleMarkerAnnotation a= it.next(); + if (a.getMarker().equals(marker)) { + return a; + } + } + return null; + } + + private void addBreakpointAnnotation(IBreakpoint breakpoint, boolean fireEvent) { + final IMarker marker= breakpoint.getMarker(); + if (marker == null) { + return; + } + try { + Position position= createPositionFromBreakpoint(breakpoint); + if (position != null) { + addAnnotation(new MarkerAnnotation(marker), position, fireEvent); + } + } catch (CoreException exc) { + // ignore problems accessing attributes + } catch (BadLocationException exc) { + // ignore wrong positions + } + } + + private Position createPositionFromBreakpoint(IBreakpoint breakpoint) throws CoreException { + if (breakpoint instanceof ICAddressBreakpoint) { + ICAddressBreakpoint addressBreakpoint= (ICAddressBreakpoint) breakpoint; + return createPositionFromAddress(decodeAddress(addressBreakpoint.getAddress())); + } else if (breakpoint instanceof ILineBreakpoint) { + ILineBreakpoint lineBreakpoint= (ILineBreakpoint) breakpoint; + Position position= null; + final int lineNumber= lineBreakpoint.getLineNumber() - 1; + final IMarker marker= breakpoint.getMarker(); + if (marker.getResource().getType() == IResource.FILE) { + position= createPositionFromSourceLine((IFile) marker.getResource(), lineNumber); + } else if (breakpoint instanceof ICLineBreakpoint) { + ICLineBreakpoint cBreakpoint= (ICLineBreakpoint) breakpoint; + position= createPositionFromSourceLine(cBreakpoint.getFileName(), lineNumber); + if (position == null) { + position= createPositionFromAddress(decodeAddress(cBreakpoint.getAddress())); + } + } else { + String fileName= marker.getAttribute(ICLineBreakpoint.SOURCE_HANDLE, null); + if (fileName != null) { + position= createPositionFromSourceLine(fileName, lineNumber); + } + } + return position; + } + return null; + } + + private Position createPositionFromSourceLine(String fileName, int lineNumber) { + return getDisassemblyDocument().getSourcePosition(fileName, lineNumber); + } + + private Position createPositionFromSourceLine(IFile file, int lineNumber) { + return getDisassemblyDocument().getSourcePosition(file, lineNumber); + } + + private Position createPositionFromAddress(BigInteger address) { + AddressRangePosition p= getDisassemblyDocument().getDisassemblyPosition(address); + if (p != null && p.fValid) { + return new Position(p.offset, p.length); + } + return null; + } + + private DisassemblyDocument getDisassemblyDocument() { + return (DisassemblyDocument) fDocument; + } + + /** + * Decode given string representation of a non-negative integer. A + * hexadecimal encoded integer is expected to start with 0x. + * + * @param string + * decimal or hexadecimal representation of an non-negative integer + * @return address value as BigInteger + */ + private static BigInteger decodeAddress(String string) { + if (string.startsWith("0x")) { //$NON-NLS-1$ + return new BigInteger(string.substring(2), 16); + } + return new BigInteger(string); + } + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + } + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentChanged(DocumentEvent event) { + if (fCatchup == null && event.fText != null && event.fText.length() > 0) { + fCatchup= new Runnable() { + public void run() { + if (fCatchup == this) { + catchupWithBreakpoints(); + fCatchup= null; + } + }}; + Display.getCurrent().timerExec(50, fCatchup); + } + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java new file mode 100644 index 00000000000..e6bc008e426 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java @@ -0,0 +1,1423 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.io.File; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IStorage; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.text.REDDocument; +import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Position; + +/** + * DisassemblyDocument + */ +public class DisassemblyDocument extends REDDocument { + + public final static String CATEGORY_MODEL = "category_model"; //$NON-NLS-1$ + public final static String CATEGORY_DISASSEMBLY = "category_disassembly"; //$NON-NLS-1$ + public final static String CATEGORY_SOURCE = "category_source"; //$NON-NLS-1$ + public final static String CATEGORY_LABELS = "category_labels"; //$NON-NLS-1$ + + private final static boolean DEBUG = false; + + public ArrayList fInvalidAddressRanges = new ArrayList(); + public ArrayList fInvalidSource = new ArrayList(); + private Map fFileInfoMap = new HashMap(); + + private int fMaxFunctionLength = 0; + + private boolean fShowAddresses = false; + private int fRadix = 16; + private boolean fShowRadixPrefix = false; + private String fRadixPrefix; + private int fNumberOfDigits; + private boolean fShowCodeBytes = false; + + private int fNumberOfInstructions; + private double fMeanSizeOfInstructions = 4; + + public DisassemblyDocument() { + super(); + } + + /* + * @see org.eclipse.jface.text.AbstractDocument#completeInitialization() + */ + @Override + protected void completeInitialization() { + super.completeInitialization(); + addPositionCategory(CATEGORY_MODEL); + addPositionCategory(CATEGORY_DISASSEMBLY); + addPositionCategory(CATEGORY_SOURCE); + addPositionCategory(CATEGORY_LABELS); + setRadix(16); + setShowRadixPrefix(false); + } + + /** + * Cleanup. + */ + @Override + public void dispose() { + super.dispose(); + if (fFileInfoMap != null) { + // cleanup source info + for (Iterator iter = fFileInfoMap.values().iterator(); iter.hasNext();) { + SourceFileInfo fi = iter.next(); + fi.dispose(); + } + fFileInfoMap = null; + } + } + + public List getInvalidAddressRanges() { + return fInvalidAddressRanges; + } + + public List getInvalidSource() { + return fInvalidSource; + } + + public void setMaxOpcodeLength(int opcodeLength) { + fMaxFunctionLength = opcodeLength; + } + + public int getMaxFunctionLength() { + return fMaxFunctionLength; + } + + public int getAddressLength() { + return fNumberOfDigits+2; + } + + public int getMeanSizeOfInstructions() { + return (int)(fMeanSizeOfInstructions+.9); + } + + public Iterator getModelPositionIterator(BigInteger address) { + try { + return getPositionIterator(CATEGORY_MODEL, address); + } catch (BadPositionCategoryException e) { + // cannot happen + } + return null; + } + + public Iterator getPositionIterator(String category, int offset) throws BadPositionCategoryException { + @SuppressWarnings("unchecked") + List positions = (List) getDocumentManagedPositions().get(category); + if (positions == null) { + throw new BadPositionCategoryException(); + } + int idx = computeIndexInPositionList(positions, offset, true); + return positions.listIterator(idx); + } + + public Iterator getPositionIterator(String category, BigInteger address) throws BadPositionCategoryException { + @SuppressWarnings("unchecked") + List positions = (List) getDocumentManagedPositions().get(category); + if (positions == null) { + throw new BadPositionCategoryException(); + } + int idx = computeIndexInPositionListFirst(positions, address); + return positions.listIterator(idx); + } + + public int computeIndexInCategory(String category, BigInteger address) throws BadPositionCategoryException { + @SuppressWarnings("unchecked") + List c = (List) getDocumentManagedPositions().get(category); + if (c == null) { + throw new BadPositionCategoryException(); + } + return computeIndexInPositionListFirst(c, address); + } + + /** + * Computes the index in the list of positions at which a position with the + * given address would be inserted. The position is supposed to become the + * first in this list of all positions with the same offset. + * + * @param positions + * the list in which the index is computed + * @param address + * the address for which the index is computed + * @return the computed index + * + */ + protected int computeIndexInPositionListFirst(List positions, BigInteger address) { + int size = positions.size(); + if (size == 0) { + return 0; + } + int left = 0; + int right = size - 1; + int mid = 0; + while (left <= right) { + mid = (left + right) / 2; + AddressRangePosition range = positions.get(mid); + if (address.compareTo(range.fAddressOffset) < 0) { + right = mid - 1; + } else if (address.compareTo(range.fAddressOffset) == 0) { + break; + } else if (address.compareTo(range.fAddressOffset.add(range.fAddressLength)) >= 0) { + left = mid + 1; + } else { + break; + } + } + int idx = mid; + AddressRangePosition p = positions.get(idx); + if (address.compareTo(p.fAddressOffset.add(p.fAddressLength)) > 0) { + ++idx; + } else if (address.compareTo(p.fAddressOffset) == 0) { + do { + --idx; + if (idx < 0) { + break; + } + p = positions.get(idx); + } while (address.compareTo(p.fAddressOffset) == 0); + ++idx; + } + return idx; + } + + /** + * Computes the index in the list of positions at which a position with the + * given address would be inserted. The position is supposed to become the + * last but one in this list of all positions with the same address. + * + * @param positions + * the list in which the index is computed + * @param address + * the address for which the index is computed + * @return the computed index + * + */ + protected int computeIndexInPositionListLast(List positions, BigInteger address) { + int size = positions.size(); + if (size == 0) { + return 0; + } + int left = 0; + int right = size - 1; + int mid = 0; + while (left <= right) { + mid = (left + right) / 2; + AddressRangePosition range = positions.get(mid); + if (address.compareTo(range.fAddressOffset) < 0) { + right = mid - 1; + } else if (address.compareTo(range.fAddressOffset) == 0) { + break; + } else if (address.compareTo(range.fAddressOffset.add(range.fAddressLength)) >= 0) { + left = mid + 1; + } else { + break; + } + } + int idx = mid; + AddressRangePosition p = positions.get(idx); + if (address.compareTo(p.fAddressOffset) > 0) { + ++idx; + } else if (address.compareTo(p.fAddressOffset) == 0 && p.fAddressLength.compareTo(BigInteger.ZERO) == 0) { + do { + ++idx; + if (idx == size) { + break; + } + p = positions.get(idx); + } while (address.compareTo(p.fAddressOffset) == 0 && p.fAddressLength.compareTo(BigInteger.ZERO) == 0); + // --idx; + } + return idx; + } + + /** + * Computes the index in the list of positions at which a position with the + * given offset would be inserted. The position is supposed to become the + * last in this list of all positions with the same offset. + * + * @param positions + * the list in which the index is computed + * @param offset + * the offset for which the index is computed + * @return the computed index + * + * @see IDocument#computeIndexInCategory(String, int) + */ + protected int computeIndexInPositionListLast(List positions, int offset) { + + if (positions.size() == 0) + return 0; + + int left = 0; + int right = positions.size() - 1; + int mid = 0; + Position p = null; + + while (left < right) { + + mid = (left + right) / 2; + + p = positions.get(mid); + if (offset < p.getOffset()) { + if (left == mid) + right = left; + else + right = mid - 1; + } else if (offset > p.getOffset()) { + if (right == mid) + left = right; + else + left = mid + 1; + } else if (offset == p.getOffset()) { + left = right = mid; + } + + } + + int pos = left; + p = positions.get(pos); + while (offset >= p.getOffset()) { + // entry will become the last of all entries with the same offset + ++pos; + if (pos == positions.size()) { + break; + } + p = positions.get(pos); + } + + assert 0 <= pos && pos <= positions.size(); + + return pos; + } + + /** + * Get the position for the supplied category and index. + * + * @param category + * @param index + * @return a Position matching the category and index, or null. + */ + public Position getPositionOfIndex(String category, int index) throws BadPositionCategoryException { + if (index >= 0) { + @SuppressWarnings("unchecked") + List positions = (List) getDocumentManagedPositions().get(category); + if (positions == null) { + throw new BadPositionCategoryException(); + } + if (index < positions.size()) { + return positions.get(index); + } + } + return null; + } + + /** + * @param address + * @return + */ + public AddressRangePosition getPositionOfAddress(BigInteger address) { + AddressRangePosition pos = getPositionOfAddress(CATEGORY_DISASSEMBLY, address); + return pos; + } + + /** + * @param category + * @param address + * @return + */ + public AddressRangePosition getPositionOfAddress(String category, BigInteger address) { + @SuppressWarnings("unchecked") + List positions = (List) getDocumentManagedPositions().get(category); + if (positions == null) { + return null; + } + int index = computeIndexInPositionListFirst(positions, address); + if (index < positions.size()) { + AddressRangePosition p = positions.get(index); + if (address.compareTo(p.fAddressOffset) == 0 || p.containsAddress(address)) { + return p; + } + } + return null; + } + + /** + * @param category + * @param range + * @return + */ + public AddressRangePosition getPositionInAddressRange(String category, AddressRangePosition range) { + @SuppressWarnings("unchecked") + List positions = (List) getDocumentManagedPositions().get(category); + if (positions == null) { + return null; + } + BigInteger endAddress = range.fAddressOffset.add(range.fAddressLength); + int index = computeIndexInPositionListFirst(positions, range.fAddressOffset); + if (index < positions.size()) { + do { + AddressRangePosition p = positions.get(index); + if (p.fAddressOffset.compareTo(endAddress) >= 0) { + --index; + } else { + return p; + } + } while (index >= 0); + } + return null; + } + + /** + * Compute the address of the given document line number. + * + * @param line + * @return the address of the given document line number, -1 if no valid + * address can be computed + */ + public BigInteger getAddressOfLine(int line) { + try { + int offset = getLineOffset(line); + return getAddressOfOffset(offset); + } catch (BadLocationException e) { + // intentionally ignored + } + return BigInteger.valueOf(-1); + } + + /** + * Compute the address off the given document offset. + * + * @param offset + * @return the address of the given document offset, -1 if no valid address + * can be computed + */ + public BigInteger getAddressOfOffset(int offset) { + AddressRangePosition pos; + try { + pos = getModelPosition(offset); + } catch (BadLocationException e) { + internalError(e); + return BigInteger.valueOf(-1); + } + if (pos == null) { + return BigInteger.valueOf(-1); + } + return pos.fAddressOffset; + } + + /** + * @param offset + * @return + */ + public AddressRangePosition getDisassemblyPosition(int offset) throws BadLocationException { + Position p = null; + try { + p = getPosition(CATEGORY_DISASSEMBLY, offset, false); + } catch (BadPositionCategoryException e) { + // cannot happen + } + return (AddressRangePosition) p; + } + + /** + * @param address + * @return + */ + public AddressRangePosition getDisassemblyPosition(BigInteger address) { + return getPositionOfAddress(CATEGORY_DISASSEMBLY, address); + } + + + /** + * @param offset + * @return + * @throws BadLocationException + */ + public AddressRangePosition getModelPosition(int offset) throws BadLocationException { + Position p = null; + try { + p = getPosition(CATEGORY_MODEL, offset, false); + } catch (BadPositionCategoryException e) { + // cannot happen + } + return (AddressRangePosition) p; + } + + /** + * @param offset + * @return + * @throws BadLocationException + */ + public SourcePosition getSourcePosition(int offset) throws BadLocationException { + Position p = null; + try { + p = getPosition(CATEGORY_SOURCE, offset, true); + } catch (BadPositionCategoryException e) { + // cannot happen + } + return (SourcePosition) p; + } + + /** + * @param address + * @return + */ + public SourcePosition getSourcePosition(BigInteger address) { + return (SourcePosition) getPositionOfAddress(CATEGORY_SOURCE, address); + } + + /** + * @param address + * @return + */ + public LabelPosition getLabelPosition(BigInteger address) { + return (LabelPosition) getPositionOfAddress(CATEGORY_LABELS, address); + } + + /** + * @param range + * @return + */ + public SourcePosition getSourcePositionInAddressRange(AddressRangePosition range) { + return (SourcePosition) getPositionInAddressRange(CATEGORY_SOURCE, range); + } + + /** + * Compute document position of the given source line. + * + * @param file the file as an IStorage + * @param lineNumber the 0-based line number + * @return the document position or null + */ + public Position getSourcePosition(IStorage file, int lineNumber) { + SourceFileInfo info= getSourceInfo(file); + return getSourcePosition(info, lineNumber); + } + + /** + * Compute document position of the given source line. + * + * @param fileName the file name, may be a raw debugger path or the path to an external file + * @param lineNumber the 0-based line number + * @return the document position or null + */ + public Position getSourcePosition(String fileName, int lineNumber) { + SourceFileInfo info= getSourceInfo(fileName); + if (info == null) { + info= getSourceInfo(new LocalFileStorage(new File(fileName))); + } + return getSourcePosition(info, lineNumber); + } + + /** + * Compute document position of the given source line. + * + * @param info + * @param lineNumber the 0-based line number + * @return the document position or null + */ + protected Position getSourcePosition(SourceFileInfo info, int lineNumber) { + if (info == null) { + return null; + } + try { + SourcePosition srcPos= null; + IRegion stmtLineRegion= info.fSource.getLineInformation(lineNumber); + final int lineOffset = stmtLineRegion.getOffset(); + final int lineLength = stmtLineRegion.getLength() + 1; + BigInteger stmtAddress = info.fLine2Addr[lineNumber]; + if (stmtAddress != null && stmtAddress.compareTo(BigInteger.ZERO) > 0) { + srcPos = getSourcePosition(stmtAddress); + } + if (srcPos == null) { + for (Iterator iterator = getPositionIterator(CATEGORY_SOURCE, 0); iterator.hasNext(); ) { + SourcePosition pos= (SourcePosition) iterator.next(); + if (pos.fFileInfo == info && pos.fValid && lineNumber >= pos.fLine) { + int baseOffset= info.fSource.getLineOffset(srcPos.fLine); + if (lineOffset + lineLength - baseOffset <= srcPos.length) { + srcPos= pos; + break; + } + } + } + if (srcPos == null) { + return null; + } + } else if (!srcPos.fValid) { + return null; + } + assert lineNumber >= srcPos.fLine; + int baseOffset = info.fSource.getLineOffset(srcPos.fLine); + int offset = srcPos.offset + lineOffset - baseOffset; + if (offset >= srcPos.offset && offset < srcPos.offset + srcPos.length) { + return new Position(offset, lineLength); + } + } catch (BadLocationException exc) { + // TLETODO Auto-generated catch block + exc.printStackTrace(); + } catch (BadPositionCategoryException exc) { + // TLETODO Auto-generated catch block + exc.printStackTrace(); + } + return null; + } + + + /** + * @param category + * @param offset + * @return + * @throws BadPositionCategoryException + * @throws BadLocationException + */ + public Position getPosition(String category, int offset, boolean allowZeroLength) throws BadLocationException, BadPositionCategoryException { + @SuppressWarnings("unchecked") + List list = (List) getDocumentManagedPositions().get(category); + int idx; + idx = computeIndexInPositionList(list, offset, true); + if (idx > 0) { + --idx; + } + while (idx < list.size()) { + Position pos = list.get(idx); + if (pos.offset > offset) { + break; + } + if (pos.includes(offset)) { + return pos; + } + if (allowZeroLength && pos.offset == offset) { + return pos; + } + ++idx; + } + return null; + } + + /** + * @param pos + */ + public void addModelPosition(AddressRangePosition pos) { + try { + addPositionLast(CATEGORY_MODEL, pos); + } catch (BadPositionCategoryException e) { + // cannot happen + } + } + + /** + * @param pos + */ + public void addModelPositionFirst(AddressRangePosition pos) { + @SuppressWarnings("unchecked") + List list = (List) getDocumentManagedPositions().get(CATEGORY_MODEL); + int idx; + idx = computeIndexInPositionListFirst(list, pos.fAddressOffset.add(pos.fAddressLength)); + if (idx < list.size()) { + AddressRangePosition nextPos = list.get(idx); + assert nextPos.fAddressOffset.compareTo(pos.fAddressOffset.add(pos.fAddressLength)) == 0; + } + list.add(idx, pos); + } + + /** + * @param pos + * @throws BadLocationException + */ + public void addDisassemblyPosition(AddressRangePosition pos) throws BadLocationException { + try { + addPositionLast(CATEGORY_DISASSEMBLY, pos); + } catch (BadPositionCategoryException e) { + // cannot happen + } + if (pos instanceof DisassemblyPosition) { + int functionLength = ((DisassemblyPosition)pos).fFunction.length; + if (functionLength > fMaxFunctionLength) { + fMaxFunctionLength = functionLength; + } + if (fNumberOfInstructions < 100) { + fMeanSizeOfInstructions = (fMeanSizeOfInstructions * fNumberOfInstructions + pos.fAddressLength.floatValue()) / (++fNumberOfInstructions); + } + } + } + + /** + * @param pos + * @throws BadPositionCategoryException + */ + public void addPositionLast(String category, AddressRangePosition pos) throws BadPositionCategoryException { + @SuppressWarnings("unchecked") + List list = (List) getDocumentManagedPositions().get(category); + if (list == null) { + throw new BadPositionCategoryException(); + } + int idx; + idx = computeIndexInPositionListLast(list, pos.fAddressOffset); + list.add(idx, pos); + } + + /** + * @param pos + * @throws BadLocationException + */ + public void addLabelPosition(AddressRangePosition pos) throws BadLocationException { + try { + addPositionLast(CATEGORY_LABELS, pos); + } catch (BadPositionCategoryException e) { + // cannot happen + } + } + + /** + * @param pos + */ + public void addSourcePosition(AddressRangePosition pos) throws BadLocationException { + try { + addPositionLast(CATEGORY_SOURCE, pos); + } catch (BadPositionCategoryException e) { + // cannot happen + } + } + + /** + * @param pos + */ + public void removeDisassemblyPosition(AddressRangePosition pos) { + try { + removePosition(CATEGORY_DISASSEMBLY, pos); + } catch (BadPositionCategoryException e) { + // cannot happen + } + } + + /** + * @param pos + */ + public void removeSourcePosition(AddressRangePosition pos) { + try { + removePosition(CATEGORY_SOURCE, pos); + } catch (BadPositionCategoryException e) { + // cannot happen + } + } + + /** + * @param pos + */ + public void removeModelPosition(AddressRangePosition pos) { + try { + removePosition(getCategory(pos), pos); + } catch (BadPositionCategoryException e) { + // cannot happen + } + } + + /** + * @param pos + * @return + */ + private static String getCategory(AddressRangePosition pos) { + if (pos instanceof LabelPosition) { + return CATEGORY_LABELS; + } else if (pos instanceof SourcePosition) { + return CATEGORY_SOURCE; + } + return CATEGORY_DISASSEMBLY; + } + + /* + * @see org.eclipse.jface.text.IDocument#removePosition(java.lang.String, + * org.eclipse.jface.text.Position) + */ + @Override + public void removePosition(String category, Position position) throws BadPositionCategoryException { + super.removePosition(category, position); + if (category != CATEGORY_MODEL && position instanceof AddressRangePosition) { + super.removePosition(CATEGORY_MODEL, position); + } + } + + @SuppressWarnings("unchecked") + public void removePositions(String category, List toRemove) { + if (toRemove.isEmpty()) { + return; + } + List positions = (List) getDocumentManagedPositions().get(category); + if (positions != null) { + positions.removeAll(toRemove); + } + if (category != CATEGORY_MODEL) { + positions = (List) getDocumentManagedPositions().get(CATEGORY_MODEL); + if (positions != null) { + positions.removeAll(toRemove); + } + } + } + + public void addPositionLast(String category, Position position) throws BadLocationException, + BadPositionCategoryException { + + if ((0 > position.offset) || (0 > position.length) || (position.offset + position.length > getLength())) + throw new BadLocationException(); + + if (category == null) + throw new BadPositionCategoryException(); + + @SuppressWarnings("unchecked") + List list = (List) getDocumentManagedPositions().get(category); + if (list == null) + throw new BadPositionCategoryException(); + + list.add(computeIndexInPositionListLast(list, position.offset), position); + } + + public void checkConsistency() { + AddressRangePosition last = null; + try { + for (Iterator it = getPositionIterator(CATEGORY_MODEL, 0); it.hasNext();) { + AddressRangePosition pos = (AddressRangePosition) it.next(); + if (last != null) { + assert last.fAddressOffset.compareTo(pos.fAddressOffset) <= 0; + assert last.fAddressOffset.add(last.fAddressLength).compareTo(pos.fAddressOffset) == 0; + assert last.offset <= pos.offset; + assert last.offset + last.length == pos.offset; + } + last = pos; + } + } catch (BadPositionCategoryException e) { + assert false; + } + } + + /** + * @param insertPos + * @param replaceLength + * @param text + * @throws BadLocationException + */ + public void replace(AddressRangePosition insertPos, int replaceLength, String text) throws BadLocationException { + int delta = (text != null ? text.length() : 0) - replaceLength; + if (delta != 0) { + BigInteger address = insertPos.fAddressOffset; + Iterator it = getModelPositionIterator(address); + while (it.hasNext()) { + AddressRangePosition pos = it.next(); + assert pos.fAddressOffset.compareTo(address) >= 0; + if (pos.fAddressOffset.compareTo(address) > 0) { + break; + } + if (pos.offset > insertPos.offset) { + break; + } + if (pos == insertPos) { + break; + } + } + while (it.hasNext()) { + AddressRangePosition pos = it.next(); + pos.offset += delta; + } + } + super.replace(insertPos.offset, replaceLength, text); + } + + /** + * @param pos + * @param insertPos + * @param line + * @throws BadPositionCategoryException + * @throws BadLocationException + */ + public AddressRangePosition insertAddressRange(AddressRangePosition pos, AddressRangePosition insertPos, String line, boolean addToModel) + throws BadLocationException { + final BigInteger address = insertPos.fAddressOffset; + BigInteger length = insertPos.fAddressLength; + if (pos == null) { + pos = getPositionOfAddress(address); + } + assert !pos.isDeleted && !pos.fValid && (length.compareTo(BigInteger.ZERO) == 0 || pos.containsAddress(address)); + int insertOffset; + int replaceLength = 0; + if (length.compareTo(BigInteger.ONE) > 0 && !pos.containsAddress(address.add(length.subtract(BigInteger.ONE)))) { + // merge with successor positions + Iterator it = getModelPositionIterator(pos.fAddressOffset.add(pos.fAddressLength)); + assert it.hasNext(); + do { + AddressRangePosition overlap = it.next(); + BigInteger posEndAddress= pos.fAddressOffset.add(pos.fAddressLength); + assert pos.offset <= overlap.offset && overlap.fAddressOffset.compareTo(posEndAddress) == 0; + if (overlap instanceof LabelPosition || overlap instanceof SourcePosition) { + // don't override label or source positions, instead fix + // length of disassembly line to insert + length = insertPos.fAddressLength = posEndAddress.subtract(address.max(pos.fAddressOffset)); + break; + } + pos.fAddressLength = pos.fAddressLength.add(overlap.fAddressLength); + replaceLength = overlap.offset + overlap.length - pos.offset - pos.length; + it.remove(); + removeModelPosition(overlap); + if (!overlap.fValid) { + fInvalidAddressRanges.remove(overlap); + } + } while(!pos.containsAddress(address.add(length.subtract(BigInteger.ONE)))); + } + BigInteger newEndAddress = pos.fAddressOffset.add(pos.fAddressLength); + BigInteger newStartAddress = address.add(length); + assert newEndAddress.compareTo(newStartAddress) >= 0; + if (address.compareTo(pos.fAddressOffset) == 0) { + // insert at start of range + insertOffset = pos.offset; + if (replaceLength == 0 && newEndAddress.compareTo(newStartAddress) > 0) { + // optimization: shrink position in place + pos.fAddressOffset = newStartAddress; + pos.fAddressLength = pos.fAddressLength.subtract(length); + // don't insert new pos + newEndAddress = newStartAddress; + } else { + replaceLength += pos.length; + fInvalidAddressRanges.remove(pos); + removeDisassemblyPosition(pos); + pos = null; + } + } else { + // insert in mid/end of range + insertOffset = pos.offset + pos.length; + pos.fAddressLength = address.subtract(pos.fAddressOffset); + assert pos.fAddressLength.compareTo(BigInteger.ZERO) > 0; + pos = null; + } + if (newEndAddress.compareTo(newStartAddress) > 0) { + pos = insertInvalidAddressRange(insertOffset+replaceLength, 0, newStartAddress, newEndAddress); + } + assert pos == null || pos.fAddressLength.compareTo(BigInteger.ZERO) > 0 && pos.containsAddress(address.add(length)); + assert insertOffset + replaceLength <= getLength(); + + insertPos.offset = insertOffset; + if (addToModel) { + addModelPosition(insertPos); + } + replace(insertPos, replaceLength, line); + if (DEBUG) checkConsistency(); + return pos; + } + + /** + * @param pos + * @param address + * @param length + * @param instruction + * @throws BadPositionCategoryException + * @throws BadLocationException + */ + public AddressRangePosition insertDisassemblyLine(AddressRangePosition pos, BigInteger address, int length, String opcode, String instruction, String file, int lineNr) + throws BadLocationException { + String disassLine = null; + if (instruction == null || instruction.length() == 0) { + disassLine = ""; //$NON-NLS-1$ + } else { + disassLine = buildDisassemblyLine(address, opcode, instruction); + } + AddressRangePosition disassPos; + if (lineNr < 0) { + disassPos = new DisassemblyPosition(0, disassLine.length(), address, BigInteger.valueOf(length), opcode); + } else { + disassPos = new DisassemblyWithSourcePosition(0, disassLine.length(), address, BigInteger.valueOf(length), + opcode, file, lineNr); + } + pos = insertAddressRange(pos, disassPos, disassLine, true); + addDisassemblyPosition(disassPos); + return pos; + } + /** + * @param address + * @param opcode + * @param instruction + */ + private String buildDisassemblyLine(BigInteger address, String opcode, String instruction) { + StringBuffer buf = new StringBuffer(40); + if (fShowAddresses) { + if (fRadixPrefix != null) { + buf.append(fRadixPrefix); + } + String str = address.toString(fRadix); + for (int i=str.length(); i 0) { + buf.append(opcode); + int tab = 16; + if (opcode.length() >= 16) { + tab = (opcode.length() + 8) & ~7; + } + int diff = tab - opcode.length(); + while (diff-- > 0) { + buf.append(' '); + } + } else if (!fShowAddresses) { + buf.append(' '); + buf.append(' '); + } + int n = instruction.length(); + int prefixLen = buf.length(); + for (int j = 0; j < n; j++) { + char ch = instruction.charAt(j); + if (ch == '\t') { + int tab = (buf.length()-prefixLen + 8) & ~0x7; + do + buf.append(' '); + while (buf.length()-prefixLen < tab); + } else { + buf.append(ch); + } + } + buf.append('\n'); + return buf.toString(); + } + + public void setRadix(int radix) { + fRadix = radix; + fNumberOfDigits = (int)(Math.log(1L<<32)/Math.log(radix)+0.9); + setShowRadixPrefix(fShowRadixPrefix); + } + + public void setShowRadixPrefix(boolean showRadixPrefix) { + fShowRadixPrefix = showRadixPrefix; + if (!fShowRadixPrefix) { + fRadixPrefix = null; + } else if (fRadix == 16) { + fRadixPrefix = "0x"; //$NON-NLS-1$ + } else if (fRadix == 8) { + fRadixPrefix = "0"; //$NON-NLS-1$ + } else { + fRadixPrefix = null; + } + } + + public AddressRangePosition insertErrorLine(AddressRangePosition pos, BigInteger address, BigInteger length, String line) + throws BadLocationException { + int hashCode = line.hashCode(); + final long alignment = 0x1L; + if (alignment > 1 && !(pos instanceof ErrorPosition)) { + AddressRangePosition before = getPositionOfAddress(address.subtract(BigInteger.ONE)); + if (before instanceof ErrorPosition && before.hashCode() == hashCode && before.offset + before.length == pos.offset) { + assert before.fAddressOffset.add(before.fAddressLength).compareTo(address) == 0; + assert pos.fAddressOffset.compareTo(address) == 0; + // merge with previous error position + BigInteger pageOffset = before.fAddressOffset.and(BigInteger.valueOf(~(alignment-1))); + BigInteger mergeLen = pageOffset.add(BigInteger.valueOf(alignment)) + .subtract((before.fAddressOffset.add(before.fAddressLength))).min(length); + if (mergeLen.compareTo(BigInteger.ZERO) > 0) { + pos.fAddressLength = pos.fAddressLength.subtract(mergeLen); + if (pos.fAddressLength.compareTo(BigInteger.ZERO) == 0) { + replace(pos, pos.length, null); + removeModelPosition(pos); + fInvalidAddressRanges.remove(pos); + pos = null; + } else { + pos.fAddressOffset = pos.fAddressOffset.add(mergeLen); + } + before.fAddressLength = before.fAddressLength.add(mergeLen); + address = address.add(mergeLen); + length = length.subtract(mergeLen); + if (DEBUG) checkConsistency(); + if (length.compareTo(BigInteger.ZERO) == 0) { + return pos; + } + } + } + AddressRangePosition after = getPositionOfAddress(address.add(length)); + if (after instanceof ErrorPosition && after.hashCode() == hashCode && pos.offset + pos.length == after.offset) { + assert after.fAddressOffset == address.add(length); + assert pos.fAddressOffset.add(pos.fAddressLength).compareTo(after.fAddressOffset) == 0; + // merge with next error position + BigInteger pageOffset = after.fAddressOffset.add(BigInteger.valueOf(~(alignment-1))); + BigInteger mergeLen = after.fAddressOffset.subtract(pageOffset).min(length); + if (mergeLen.compareTo(BigInteger.ZERO) > 0) { + after.fAddressOffset = after.fAddressOffset.subtract(mergeLen); + after.fAddressLength = after.fAddressLength.add(mergeLen); + pos.fAddressLength = pos.fAddressLength.subtract(mergeLen); + if (pos.fAddressLength.compareTo(BigInteger.ZERO) == 0) { + replace(pos, pos.length, null); + removeModelPosition(pos); + fInvalidAddressRanges.remove(pos); + pos = null; + } + if (DEBUG) checkConsistency(); + length = length.subtract(mergeLen); + if (length.compareTo(BigInteger.ZERO) == 0) { + return pos; + } + } + } + } + BigInteger pageOffset = address.and(BigInteger.valueOf(~(alignment-1))); + BigInteger posLen = pageOffset.add(BigInteger.valueOf(alignment)).subtract(address).min(length); + while (length.compareTo(BigInteger.ZERO) > 0) { + AddressRangePosition errorPos = new ErrorPosition(0, 0, address, posLen, hashCode); + String errorLine = buildDisassemblyLine(address, null, line); + // TLEHACK: check for error messages, which occur only temporarily: + // "Target is busy. Try again later" + // "Cannot Perform requested Operation" + if (line.startsWith("Target is busy") || line.startsWith("Cannot perform")) { //$NON-NLS-1$ //$NON-NLS-2$ + // try again only once... + if (!(pos instanceof ErrorPosition)) { + errorLine = "...\n"; //$NON-NLS-1$ + errorPos.fValid = false; + } + } + errorPos.length = errorLine.length(); + pos = insertAddressRange(pos, errorPos, errorLine, true); + addDisassemblyPosition(errorPos); + if (!errorPos.fValid) { + fInvalidAddressRanges.add(errorPos); + } + length = length.subtract(posLen); + address = address.add(posLen); + posLen = BigInteger.valueOf(alignment).min(length); + } + return pos; + } + + /** + * @param pos + * @param address + * @param label + * @throws BadLocationException + * @throws BadPositionCategoryException + */ + public AddressRangePosition insertLabel(AddressRangePosition pos, BigInteger address, String label, boolean showLabels) + throws BadLocationException { + String labelLine = showLabels ? label + ":\n" : ""; //$NON-NLS-1$ //$NON-NLS-2$ + LabelPosition labelPos = getLabelPosition(address); + if (labelPos != null) { + assert labelPos.fAddressOffset.compareTo(address) == 0; + if (labelPos.length != labelLine.length()) { + int oldLength = labelPos.length; + labelPos.length = labelLine.length(); + replace(labelPos, oldLength, labelLine); + } + return pos; + } + labelPos = new LabelPosition(0, labelLine.length(), address, null); + pos = insertAddressRange(pos, labelPos, labelLine, true); + addLabelPosition(labelPos); + return pos; + } + + /** + * @param pos + * @param address + * @param source + * @param line + * @param endOfSource + * @throws BadLocationException + * @throws BadPositionCategoryException + */ + public SourcePosition insertSource(SourcePosition pos, String source, int line, boolean endOfSource) { +// System.out.println("insertSource at "+getAddressText(pos.fAddressOffset)); +// System.out.println(source); + String sourceLines = source; + if (source.length() > 0 && sourceLines.charAt(source.length() - 1) != '\n') { + sourceLines += "\n"; //$NON-NLS-1$ + } + try { + assert !pos.fValid; + int oldLength = pos.length; + pos.length = sourceLines.length(); + pos.fLine = line; + pos.fValid = true; + fInvalidSource.remove(pos); + replace(pos, oldLength, sourceLines); + if (!endOfSource) { + if (pos.length > 0) { + SourcePosition oldPos = getSourcePosition(pos.offset+pos.length); + if (oldPos == null || oldPos.fAddressOffset.compareTo(pos.fAddressOffset) != 0) { + pos = new SourcePosition(pos.offset+pos.length, 0, pos.fAddressOffset, pos.fFileInfo, line, false); + addSourcePosition(pos); + addModelPosition(pos); + fInvalidSource.add(pos); + } else { + //TLETODO need more checks for correct source pos + pos = oldPos; + } + } + } + } catch (BadLocationException e) { + internalError(e); + } + return pos; + } + + /** + * @param pos + * @param address + * @param fi + * @param lineNr + * @return + */ + public AddressRangePosition insertInvalidSource(AddressRangePosition pos, BigInteger address, SourceFileInfo fi, int lineNr) { + SourcePosition sourcePos = getSourcePosition(address); + if (sourcePos != null) { + return pos; + } + String sourceLine = ""; //$NON-NLS-1$ + sourcePos = new SourcePosition(0, sourceLine.length(), address, fi, lineNr, false); + try { + pos = insertAddressRange(pos, sourcePos, sourceLine, true); + addSourcePosition(sourcePos); + assert !fInvalidSource.contains(sourcePos); + fInvalidSource.add(sourcePos); + } catch (BadLocationException e) { + internalError(e); + } + return pos; + } + + /** + * @param offset + * @param replaceLength + * @param startAddress + * @param endAddress + * @return + */ + public AddressRangePosition insertInvalidAddressRange(int offset, int replaceLength, BigInteger startAddress, BigInteger endAddress) { + String periods = "...\n"; //$NON-NLS-1$ + AddressRangePosition newPos = new AddressRangePosition(offset, periods.length(), startAddress, endAddress + .subtract(startAddress), false); + try { + addModelPositionFirst(newPos); + replace(newPos, replaceLength, periods); + addDisassemblyPosition(newPos); + fInvalidAddressRanges.add(newPos); + } catch (BadLocationException e) { + internalError(e); + } + return newPos; + } + + public void invalidateAddressRange(BigInteger startAddress, BigInteger endAddress, boolean collapse) { + deleteDisassemblyRange(startAddress, endAddress, true, collapse); + } + + public void deleteDisassemblyRange(BigInteger startAddress, BigInteger endAddress, boolean invalidate, boolean collapse) { + String replacement = invalidate ? "...\n" : null; //$NON-NLS-1$ + int replaceLen = replacement != null ? replacement.length() : 0; + AddressRangePosition lastPos = null; + ArrayList toRemove = new ArrayList(); + Iterator it = getModelPositionIterator(startAddress); + while (it.hasNext()) { + AddressRangePosition pos = it.next(); + BigInteger posEndAddress = pos.fAddressOffset.add(pos.fAddressLength); + if (pos instanceof LabelPosition) { + if (!invalidate && pos.length > 0 && posEndAddress.compareTo(endAddress) > 0) { + try { + int oldLength = pos.length; + pos.length = 0; + replace(pos, oldLength, null); + } catch (BadLocationException e) { + internalError(e); + } + } + pos = null; + } else if (pos instanceof SourcePosition) { + pos = null; + } else if (pos instanceof ErrorPosition) { + pos = null; + } else if (pos instanceof DisassemblyPosition) { + // optimization: join adjacent positions + if (collapse && lastPos != null + && (invalidate || lastPos.fValid == pos.fValid) + && lastPos.offset+lastPos.length == pos.offset) { + assert lastPos.fAddressOffset.add(lastPos.fAddressLength).compareTo(pos.fAddressOffset) == 0; + lastPos.length += pos.length; + lastPos.fAddressLength = lastPos.fAddressLength.add(pos.fAddressLength); + toRemove.add(pos); + if (!pos.fValid) { + fInvalidAddressRanges.remove(pos); + } + pos = null; + if (posEndAddress.compareTo(endAddress) < 0) { + continue; + } + } + } + if (lastPos != null) { + try { + if (lastPos.length > 0 || replaceLen > 0) { + int oldLength = lastPos.length; + lastPos.length = replaceLen; + replace(lastPos, oldLength, replacement); + } + } catch (BadLocationException e) { + internalError(e); + } + } + if (pos == null && posEndAddress.compareTo(endAddress) >= 0) { + break; + } + lastPos = null; + if (pos != null) { + if (pos.fValid && invalidate) { + pos.fValid = false; + fInvalidAddressRanges.add(pos); + } + lastPos = pos; + } + } + removePositions(CATEGORY_DISASSEMBLY, toRemove); + if (DEBUG) checkConsistency(); + } + + public void invalidateSource() { + Iterator it; + try { + it = getPositionIterator(CATEGORY_SOURCE, 0); + } catch (BadPositionCategoryException e) { + internalError(e); + return; + } + while (it.hasNext()) { + SourcePosition srcPos = (SourcePosition)it.next(); + if (srcPos != null && srcPos.fValid) { + srcPos.fValid = false; + assert !getInvalidSource().contains(srcPos); + getInvalidSource().add(srcPos); + } + } + } + + public void invalidateDisassemblyWithSource(boolean removeDisassembly) { + for (Iterator it = fFileInfoMap.values().iterator(); it.hasNext();) { + SourceFileInfo info = it.next(); + if (info.fLine2Addr != null) { + deleteDisassemblyRange(info.fStartAddress, info.fEndAddress.add(BigInteger.ONE), !removeDisassembly, !removeDisassembly); + } + } + } + + /** + * @param start + * @param end + * @throws BadLocationException + */ + public void deleteLineRange(int start, int end) throws BadLocationException { + if (start >= end) { + return; + } + int startOffset = getLineOffset(start); + int endOffset = getLineOffset(end); + int replaceLength = 0; + AddressRangePosition startPos = getDisassemblyPosition(startOffset); + if (startPos == null) { + return; + } + startOffset = startPos.offset; + AddressRangePosition endPos = getDisassemblyPosition(endOffset); + if (endPos == null) { + return; + } + BigInteger startAddress = BigInteger.ZERO; + BigInteger addressLength = BigInteger.ZERO; + ArrayList toRemove = new ArrayList(); + try { + Iterator it = getPositionIterator(DisassemblyDocument.CATEGORY_MODEL, startAddress); + while (it.hasNext()) { + AddressRangePosition p = it.next(); + addressLength = addressLength.add(p.fAddressLength); + replaceLength += p.length; + toRemove.add(p); + if (!p.fValid) { + if (p instanceof SourcePosition) { + getInvalidSource().remove(p); + } else { + getInvalidAddressRanges().remove(p); + } + } + if (addressLength.compareTo(BigInteger.ZERO) > 0 && p.fAddressOffset.compareTo(endPos.fAddressOffset) >= 0) { + break; + } + } + } catch (BadPositionCategoryException e) { + // cannot happen + } + for (Iterator iter = toRemove.iterator(); iter.hasNext();) { + AddressRangePosition pos = iter.next(); + removeModelPosition(pos); + } + if (addressLength.compareTo(BigInteger.ZERO) > 0) { + insertInvalidAddressRange(startOffset, replaceLength, startAddress, startAddress.add(addressLength)); + } + } + + public SourceFileInfo getSourceInfo(BigInteger address) { + AddressRangePosition pos = getDisassemblyPosition(address); + if (pos instanceof DisassemblyPosition) { + DisassemblyPosition disassPos = (DisassemblyPosition)pos; + return getSourceInfo(disassPos.getFile()); + } + return null; + } + + public SourceFileInfo getSourceInfo(String file) { + if (fFileInfoMap == null || file == null) { + return null; + } + for (Iterator iter = fFileInfoMap.values().iterator(); iter.hasNext();) { + SourceFileInfo info = iter.next(); + if (file.equals(info.fFileKey)) { + return info; + } + } + return null; + } + + public SourceFileInfo getSourceInfo(IStorage sourceElement) { + if (fFileInfoMap == null) { + return null; + } + SourceFileInfo fi = fFileInfoMap.get(sourceElement); + return fi; + } + + public SourceFileInfo createSourceInfo(String fileKey, IStorage sourceElement, Runnable done) { + SourceFileInfo fi = new SourceFileInfo(fileKey, sourceElement); + assert fFileInfoMap != null; + if (fFileInfoMap != null) { + fFileInfoMap.put(sourceElement, fi); + new SourceReadingJob(fi, done); + } + return fi; + } + + private void internalError(Throwable e) { + if (DEBUG) { + System.err.println("Disassembly: Internal error"); //$NON-NLS-1$ + e.printStackTrace(); + } + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java new file mode 100644 index 00000000000..8b2010cd515 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + +/** + * DisassemblyPosition + */ +public class DisassemblyPosition extends AddressRangePosition { + + public char[] fFunction; + + /** + * + * @param offset + * @param length + * @param addressOffset + * @param addressLength + * @param opcodes + */ + public DisassemblyPosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, String opcodes) { + super(offset, length, addressOffset, addressLength); + fFunction = opcodes.toCharArray(); + } + + /** + * @return source file + */ + public String getFile() { + return null; + } + + /** + * @return source line number + */ + public int getLine() { + return -1; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java new file mode 100644 index 00000000000..55e537e5935 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + +/** + * DisassemblyWithSourcePosition + */ +public class DisassemblyWithSourcePosition extends DisassemblyPosition { + + private String fFile; + private int fLine; + + /** + * @param offset + * @param length + * @param addressOffset + * @param addressLength + * @param opcodes + */ + public DisassemblyWithSourcePosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, String opcodes, String file, int lineNr) { + super(offset, length, addressOffset, addressLength, opcodes); + fFile = file; + fLine = lineNr; + } + + /* (non-Javadoc) + * @see com.windriver.ide.disassembly.model.DisassemblyPosition#getFile() + */ + @Override + public String getFile() { + return fFile; + } + + /* (non-Javadoc) + * @see com.windriver.ide.disassembly.model.DisassemblyPosition#getLine() + */ + @Override + public int getLine() { + return fLine; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java new file mode 100644 index 00000000000..93be42f3f7a --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + +/** + * ErrorPosition + */ +public class ErrorPosition extends AddressRangePosition { + + public int fHashCode; + + /** + * @param offset + * @param length + * @param addressOffset + * @param addressLength + */ + public ErrorPosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, int hashCode) { + super(offset, length, addressOffset, addressLength); + fHashCode = hashCode; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return fHashCode; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/LabelPosition.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/LabelPosition.java new file mode 100644 index 00000000000..88157414d89 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/LabelPosition.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + +/** + * LabelPosition + */ +public class LabelPosition extends AddressRangePosition { + + public String fLabel; + + /** + * @param offset + * @param length + * @param addressOffset + */ + public LabelPosition(int offset, int length, BigInteger addressOffset, String label) { + super(offset, length, addressOffset, BigInteger.ZERO); + fLabel = label; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java new file mode 100644 index 00000000000..c9a1dfb8233 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.util.Iterator; + +import org.eclipse.cdt.internal.ui.editor.CDocumentSetupParticipant; +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFileState; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.text.REDDocument; +import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.ui.IStorageEditorInput; +import org.eclipse.ui.IURIEditorInput; +import org.eclipse.ui.editors.text.StorageDocumentProvider; + +/** + * SourceDocumentProvider + */ +public class SourceDocumentProvider extends StorageDocumentProvider { + + public SourceDocumentProvider() { + super(); + } + + /** + * Dispose all connected documents. + */ + public void dispose() { + Iterator it = getConnectedElements(); + while(it.hasNext()) { + Object element = it.next(); + ElementInfo info = getElementInfo(element); + // force refcount to 1 + info.fCount = 1; + disconnect(element); + } + } + + /* + * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#createDocument(java.lang.Object) + */ + @Override + protected IDocument createEmptyDocument() { + IDocument doc = new REDDocument(); + return doc; + } + + /* + * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#createAnnotationModel(java.lang.Object) + */ + @Override + protected IAnnotationModel createAnnotationModel(Object element) throws CoreException { + return null; + } + + /* + * @see org.eclipse.ui.editors.text.StorageDocumentProvider#setupDocument(java.lang.Object, org.eclipse.jface.text.IDocument) + */ + @Override + protected void setupDocument(Object element, IDocument document) { + super.setupDocument(element, document); + if (element instanceof IStorageEditorInput) { + new CDocumentSetupParticipant().setup(document); + } + } + + /* + * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#disposeElementInfo(java.lang.Object, org.eclipse.ui.texteditor.AbstractDocumentProvider.ElementInfo) + */ + @Override + protected void disposeElementInfo(Object element, ElementInfo info) { + super.disposeElementInfo(element, info); + IDocument doc = info.fDocument; + if (doc instanceof REDDocument) { + ((REDDocument)doc).dispose(); + } + } + + /* + * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#getModificationStamp(java.lang.Object) + */ + @Override + public long getModificationStamp(Object element) { + try { + if (element instanceof IStorageEditorInput) { + IStorage file= ((IStorageEditorInput)element).getStorage(); + if (file instanceof IFile) { + return ((IFile)file).getLocalTimeStamp(); + } else if (file instanceof IFileState) { + return ((IFileState)file).getModificationTime(); + } else if (file instanceof LocalFileStorage) { + return ((LocalFileStorage)file).getFile().lastModified(); + } + } else if (element instanceof IURIEditorInput) { + return EFS.getStore(((IURIEditorInput)element).getURI()).fetchInfo().getLastModified(); + } + } catch (CoreException e) { + // ignore + } + return 0; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java new file mode 100644 index 00000000000..df7ebc592f1 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import org.eclipse.core.resources.IStorage; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.util.StorageEditorInput; + +/** + * SourceEditorInput + */ +public class SourceEditorInput extends StorageEditorInput { + + /** + * @param storage + */ + public SourceEditorInput(IStorage storage) { + super(storage); + } + + /* + * @see org.eclipse.ui.IEditorInput#exists() + */ + public boolean exists() { + return false; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java new file mode 100644 index 00000000000..97522e9031c --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.presentation.ISourcePresentationCreator; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.presentation.SourcePresentationCreatorFactory; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.ui.IEditorInput; + +/** + * Holds information about a source file. + */ +public class SourceFileInfo { + public final String fFileKey; + public final IStorage fFile; + public IStorage fEdition; + public BigInteger[] fLine2Addr; + public Addr2Line[] fAddr2Line; + public volatile IDocument fSource; + public volatile boolean fValid; + public Object fLinesNode; + public Throwable fError; + public volatile SourceReadingJob fReadingJob; + public volatile Job fEditionJob; + public ISourcePresentationCreator fPresentationCreator; + public BigInteger fStartAddress = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE); + public BigInteger fEndAddress= BigInteger.ZERO; + + public SourceFileInfo(String fileKey, IStorage file) { + fFileKey = fileKey; + fFile = fEdition = file; + } + + /** + * Initialize source document. + * @throws CoreException + */ + public void initSource() throws CoreException { + SourceDocumentProvider provider = DsfDebugUIPlugin.getSourceDocumentProvider(); + IEditorInput input = new SourceEditorInput(fEdition); + synchronized (provider) { + provider.connect(input); + } + IStatus status = provider.getStatus(input); + if (status != null && !status.isOK()) { + throw new CoreException(status); + } + } + + /** + * Initialize presentation creator. + * @param viewer + */ + public void initPresentationCreator(ITextViewer viewer) { + SourceDocumentProvider provider = DsfDebugUIPlugin.getSourceDocumentProvider(); + IEditorInput input = new SourceEditorInput(fEdition); + IDocument doc = provider.getDocument(input); + if (doc != null) { + IContentType contentType= null; + if (fEdition instanceof IFile) { + IFile file= (IFile)fEdition; + contentType= CCorePlugin.getContentType(file.getProject(), file.getName()); + } else { + contentType= CCorePlugin.getContentType(fEdition.getName()); + } + ILanguage language= null; + if (contentType != null) { + language= LanguageManager.getInstance().getLanguage(contentType); + } + if (language != null) { + fPresentationCreator= SourcePresentationCreatorFactory.create(language, fEdition, viewer); + } + int lines = doc.getNumberOfLines(); + fLine2Addr = new BigInteger[lines]; + fAddr2Line = new Addr2Line[lines / 10 + 1]; + // assign fSource last, triggering source update + fSource = doc; + } + } + + /** + * Dispose this object. + */ + public void dispose() { + if (fReadingJob != null) { + if (!fReadingJob.cancel()) { + fReadingJob.dispose(); + } + fReadingJob = null; + } + if (fPresentationCreator != null) { + fPresentationCreator.dispose(); + fPresentationCreator = null; + } + SourceDocumentProvider provider = DsfDebugUIPlugin.getSourceDocumentProvider(); + synchronized (provider) { + provider.disconnect(new SourceEditorInput(fEdition)); + } + fSource = null; + fValid = false; +// fLinesNode = null; + } + + public String getLine(int lineNr) { + return getLines(lineNr, lineNr); + } + + public String getLines(int first, int last) { + try { + int startOffset = fSource.getLineOffset(first); + int endOffset; + if (last < fSource.getNumberOfLines()-1) { + IRegion lastRegion = fSource.getLineInformation(last+1); + endOffset = lastRegion.getOffset(); + } else { + // last line + IRegion lastRegion = fSource.getLineInformation(last); + endOffset = lastRegion.getOffset() + lastRegion.getLength(); + } + return fSource.get(startOffset, endOffset - startOffset); + } catch (BadLocationException e) { + return null; + } + } + + public IRegion getRegion(int line, int length) { + try { + IRegion lineRegion = fSource.getLineInformation(line); + return new Region(lineRegion.getOffset(), length); + } catch (BadLocationException e) { + return null; + } + } + + /** + * Get or create text presentation for the given region. + * Must be called in display thread. + * @param region + * @return text presentation + */ + public TextPresentation getPresentation(IRegion region) { + if (fSource != null && fPresentationCreator != null) { + return fPresentationCreator.getPresentation(region, fSource); + } + return null; + } + + /** + * @return offset of given line + */ + public int getLineOffset(int line) { + if (fSource != null) { + try { + return fSource.getLineOffset(line); + } catch (BadLocationException e) { + // ignored + } + } + return -1; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourcePosition.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourcePosition.java new file mode 100644 index 00000000000..e03699948e2 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourcePosition.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import java.math.BigInteger; + +/** + * SourcePosition + */ +public class SourcePosition extends AddressRangePosition { + + public SourceFileInfo fFileInfo; + public int fLine; + + /** + * + * @param offset + * @param length + * @param addressOffset + * @param fileInfo + * @param line + */ + public SourcePosition(int offset, int length, BigInteger addressOffset, SourceFileInfo fileInfo, int line) { + this(offset, length, addressOffset, fileInfo, line, true); + } + + /** + * + * @param offset + * @param length + * @param addressOffset + * @param fileInfo + * @param line + * @param valid + */ + public SourcePosition(int offset, int length, BigInteger addressOffset, SourceFileInfo fileInfo, int line, boolean valid) { + super(offset, length, addressOffset, BigInteger.ZERO, valid); + fFileInfo = fileInfo; + fLine = line; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java new file mode 100644 index 00000000000..54e87a68596 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.model; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages; + + +/** + * Low-level job to read source files in the background. + */ +public class SourceReadingJob extends Job { + + private final static String NAME = DisassemblyMessages.SourceReadingJob_name; + + private SourceFileInfo fFileInfo; + private Runnable fDone; + + public SourceReadingJob(SourceFileInfo fi, Runnable done) { + super(NAME); + fFileInfo = fi; + fFileInfo.fReadingJob = this; + fDone = done; + if (fi.fFile instanceof ISchedulingRule) { + setRule((ISchedulingRule)fi.fFile); + } + setSystem(true); + // usually short lived job + setPriority(SHORT); + if (fi.fFile.getFullPath() != null) { + String fileName = fi.fFile.getFullPath().lastSegment(); + setName(NAME + " (" + fileName + ')'); //$NON-NLS-1$ + } + } + + public synchronized void dispose() { + fDone = null; + Thread thread = getThread(); + if (thread != null && thread.isAlive()) { + thread.interrupt(); + } + } + + @Override + public IStatus run(IProgressMonitor monitor) { + if (fFileInfo.fEditionJob != null) { + try { + fFileInfo.fEditionJob.join(); + } catch (InterruptedException e) { + // ignore + } + } + try { + fFileInfo.initSource(); + } catch (Throwable e) { + fFileInfo.fError = e; + } finally { + fFileInfo.fReadingJob = null; + synchronized (this) { + if (fDone != null && !getThread().isInterrupted()) { + fDone.run(); + } + } + } + // errors are handled elsewhere + return Status.OK_STATUS; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java new file mode 100644 index 00000000000..1b6415dc400 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.preferences; + +import java.math.BigInteger; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.editors.text.TextEditorPreferenceConstants; + +/** + * DisassemblyPreferenceConstants + */ +public class DisassemblyPreferenceConstants { + + public static final String START_ADDRESS = "startAddress"; //$NON-NLS-1$ + public static final String END_ADDRESS = "endAddress"; //$NON-NLS-1$ + public static final String PC_HISTORY_SIZE = "pcHistorySize"; //$NON-NLS-1$ + public static final String SHOW_SOURCE = "showSource"; //$NON-NLS-1$ + public static final String SHOW_LABELS = "showLabels"; //$NON-NLS-1$ + public static final String SHOW_SYMBOLS = "showSymbols"; //$NON-NLS-1$ + public static final String SIMPLIFIED = "simplified"; //$NON-NLS-1$ + public static final String INSTRUCTION_RADIX = "instructionRadix"; //$NON-NLS-1$ + public static final String ADDRESS_RADIX = "addressRadix"; //$NON-NLS-1$ + public static final String SHOW_ADDRESS_RADIX = "showAddressRadix"; //$NON-NLS-1$ + public static final String SHOW_ADDRESS_RULER = "showAddressRuler"; //$NON-NLS-1$ + public static final String ADDRESS_COLOR = "addressColor"; //$NON-NLS-1$ + public static final String SHOW_FUNCTION_OFFSETS = "showOpcodeRuler"; //$NON-NLS-1$ + public static final String OPCODE_COLOR = "opcodeColor"; //$NON-NLS-1$ + public static final String USE_SOURCE_ONLY_MODE = "useSourceOnlyMode"; //$NON-NLS-1$ + public static final String AVOID_READ_BEFORE_PC = "avoidReadBeforePC"; //$NON-NLS-1$ + + /** + * + */ + private DisassemblyPreferenceConstants() { + // not intended to be subclassed or instatiated + } + + /** + * Initialize preference default values. + * @param store + */ + public static void initializeDefaults(IPreferenceStore store) { + TextEditorPreferenceConstants.initializeDefaultValues(store); + store.setDefault(START_ADDRESS, 0x0L); + store.setDefault(END_ADDRESS, "0x" + BigInteger.ONE.shiftLeft(64).toString(16)); //$NON-NLS-1$ + store.setDefault(PC_HISTORY_SIZE, 4); + store.setDefault(SHOW_SOURCE, true); + store.setDefault(SHOW_FUNCTION_OFFSETS, false); + store.setDefault(SHOW_LABELS, true); + store.setDefault(SHOW_SYMBOLS, true); + store.setDefault(SIMPLIFIED, true); + store.setDefault(INSTRUCTION_RADIX, 16); + store.setDefault(ADDRESS_RADIX, 16); + store.setDefault(SHOW_ADDRESS_RADIX, false); + store.setDefault(SHOW_ADDRESS_RULER, true); + store.setDefault(AVOID_READ_BEFORE_PC, false); + store.setDefault(USE_SOURCE_ONLY_MODE, false); + PreferenceConverter.setDefault(store, ADDRESS_COLOR, new RGB(0, 96, 0)); + PreferenceConverter.setDefault(store, OPCODE_COLOR, new RGB(96, 0, 0)); + } + + public static class Initializer extends AbstractPreferenceInitializer { + @Override + public void initializeDefaultPreferences() { + IPreferenceStore store = DsfDebugUIPlugin.getDefault().getPreferenceStore(); + initializeDefaults(store); + EditorsUI.useAnnotationsPreferencePage(store); + } + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java new file mode 100644 index 00000000000..372eaab2cbb --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.ui.disassembly.preferences; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyMessages; +import org.eclipse.dd.dsf.debug.internal.ui.disassembly.IDisassemblyHelpContextIds; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +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.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.PlatformUI; + +/** + * DisassemblyPreferencePage + */ +public class DisassemblyPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + + private List