org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyPart.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.dd.dsf.debug.internal.ui.disassembly.DisassemblyPart.java

Source

/*******************************************************************************
 * 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.Platform;
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
 */
@SuppressWarnings("restriction")
public abstract class DisassemblyPart extends WorkbenchPart
        implements IDisassemblyPart, IViewportListener, ITextPresentationListener, SessionEndedListener {

    private final static boolean DEBUG = "true" //$NON-NLS-1$
            .equals(Platform.getDebugOption("org.eclipse.dd.dsf.debug.ui/disassembly")); //$NON-NLS-1$

    /**
     * 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 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<BigInteger> fPendingPCUpdates = new ArrayList<BigInteger>(5);
    private Position fScrollPos;
    private int fScrollLine;
    private Position fFocusPos;
    private BigInteger fFrameAddress = PC_UNKNOWN;
    protected Map<String, Action> fGlobalActions = new HashMap<String, Action>();
    private List<Action> fSelectionActions = new ArrayList<Action>();
    private List<AbstractDisassemblyAction> fStateDependentActions = new ArrayList<AbstractDisassemblyAction>();
    private boolean fSourceOnlyMode;
    private boolean fShowSource;
    private boolean fShowOpcodes;
    private boolean fShowSymbols;
    private Map<String, Object> fFile2Storage = new HashMap<String, Object>();
    private boolean fShowDisassembly;
    private LinkedList<AddressRangePosition> fPCHistory = new LinkedList<AddressRangePosition>();
    private int fPCHistorySizeMax = 4;
    private boolean fGotoFramePending;

    private String fPCAnnotationColorKey;

    private ArrayList<Runnable> fRunnableQueue = new ArrayList<Runnable>();

    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<IHandlerActivation> 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_UNKNOWN;
        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
    @SuppressWarnings("unchecked")
    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.
     * <p>
     * Subclasses may extend.
     * </p>
     *
     * @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<AddressRangePosition> 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();
        }
        DsfSession.addSessionEndedListener(this);
    }

    /*
     * @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;
        setDebugContext(null);
        DsfSession.removeSessionEndedListener(this);

        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 <code>null</code> 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<String> 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();
        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<Action> iterator = fSelectionActions.iterator();
        while (iterator.hasNext()) {
            IUpdate action = (IUpdate) iterator.next();
            action.update();
        }
    }

    protected void updateStateDependentActions() {
        Iterator<AbstractDisassemblyAction> 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<IHandlerActivation>(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<FormattedValueDMData>(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<AddressRangePosition> 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<SourcePosition> copy = new ArrayList<SourcePosition>(fDocument.getInvalidSource());
            Iterator<SourcePosition> 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 " //$NON-NLS-1$
                            + getAddressText(p.fAddressOffset));
                }
            }
        } 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<String> query = new Query<String>() {
            @Override
            protected void execute(final DataRequestMonitor<String> rm) {
                final DataRequestMonitor<String> request = new DataRequestMonitor<String>(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<IMixedInstruction[]> disassemblyRequest = new DataRequestMonitor<IMixedInstruction[]>(
                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<IMixedInstruction[]> disassemblyRequest = new DataRequestMonitor<IMixedInstruction[]>(
                    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<IInstruction[]> disassemblyRequest = new DataRequestMonitor<IInstruction[]>(
                    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<IFrameDMContext> request = new DataRequestMonitor<IFrameDMContext>(
                            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<IFrameDMData> request = new DataRequestMonitor<IFrameDMData>(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<AddressRangePosition> positions = fDocument.getInvalidAddressRanges();
            List<AddressRangePosition> toRemove = new ArrayList<AddressRangePosition>();
            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);
    }

    /**
     * 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) {
                    if (fDebugSessionId != null) {
                        if (getSession() != null) {
                            getSession().removeServiceEventListener(this);
                        }
                    }
                    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 (fServicesTracker != null) {
                fServicesTracker.dispose();
                fServicesTracker = 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);
            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);
    }

    /*
     * @see org.eclipse.dd.dsf.service.DsfSession.SessionEndedListener#sessionEnded(org.eclipse.dd.dsf.service.DsfSession)
     */
    public void sessionEnded(DsfSession endedSsession) {
        if (endedSsession.getId().equals(fDebugSessionId)) {
            asyncExec(new Runnable() {
                public void run() {
                    setDebugContext(null);
                }
            });
        }
    }

    @DsfServiceEventHandler
    public void handleEvent(IExitedDMEvent event) {
        final IExecutionDMContext context = event.getDMContext();
        if (context.equals(fTargetContext) || DMContexts.isAncestorOf(fTargetContext, context)) {
            asyncExec(new Runnable() {
                public void run() {
                    setDebugContext(null);
                }
            });
        }
    }

    @DsfServiceEventHandler
    public void handleEvent(ISuspendedDMEvent event) {
        final IExecutionDMContext context = event.getDMContext();
        if (context.equals(fTargetContext) || DMContexts.isAncestorOf(fTargetContext, context)) {
            asyncExec(new Runnable() {
                public void run() {
                    updatePC(PC_UNKNOWN);
                    firePropertyChange(PROP_SUSPENDED);
                }
            });
        }
    }

    @DsfServiceEventHandler
    public void handleEvent(IResumedDMEvent event) {
        final IExecutionDMContext context = event.getDMContext();
        if (context.equals(fTargetContext) || DMContexts.isAncestorOf(fTargetContext, context)) {
            asyncExec(new Runnable() {
                public void run() {
                    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<SimpleMarkerAnnotation> it = bpModel.getAnnotationIterator(offset, length, true, true);
                List<IBreakpoint> bpList = new ArrayList<IBreakpoint>(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> V getService(Class<V> 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 <code>Long</code> object in case the value was computed,
     * another object to be waited on if the retrieval is in progress, <code>null</code>
     * if no time stamp could be retrieved.
     * 
     * @param address
     * @return Long, Object or <code>null</code>
     */
    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<AddressRangePosition> 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<Runnable> copy = new ArrayList<Runnable>(fRunnableQueue);
                fRunnableQueue.clear();
                for (Iterator<Runnable> 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)
     */
    @SuppressWarnings("unchecked")
    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<Position> 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<StyleRange> styleRanges = new ArrayList<StyleRange>();
        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<StyleRange> 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<StyleRange> 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<AddressRangePosition> 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, "", //$NON-NLS-1$
                    true);
        }

        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<Object> query = new Query<Object>() {
                @Override
                protected void execute(final DataRequestMonitor<Object> rm) {
                    final DataRequestMonitor<Object> request = new DataRequestMonitor<Object>(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 "<null>"; //$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();
        }
    }

}