| /******************************************************************************* |
| * Copyright (c) 2010, 2016 Wind River Systems, Inc. and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| * Freescale Semiconductor - refactoring |
| * Patrick Chuong (Texas Instruments) - Bug 323279 |
| * Patrick Chuong (Texas Instruments) - Bug 329682 |
| * Patrick Chuong (Texas Instruments) - Bug 328168 |
| * Patrick Chuong (Texas Instruments) - Bug 353351 |
| * Patrick Chuong (Texas Instruments) - Bug 337851 |
| * William Riley (Renesas) - Bug 357270 |
| *******************************************************************************/ |
| package org.eclipse.cdt.dsf.debug.internal.ui.disassembly; |
| |
| import static org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils.DEBUG; |
| import static org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils.internalError; |
| |
| import java.math.BigInteger; |
| import java.text.MessageFormat; |
| import java.util.List; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.RejectedExecutionException; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| |
| import org.eclipse.cdt.core.IAddress; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AbstractDisassemblyBackend; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AddressRangePosition; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.ErrorPosition; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyPartCallback; |
| import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; |
| import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.DsfExecutor; |
| import org.eclipse.cdt.dsf.concurrent.DsfRunnable; |
| import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; |
| import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.Query; |
| import org.eclipse.cdt.dsf.datamodel.DMContexts; |
| import org.eclipse.cdt.dsf.datamodel.IDMContext; |
| import org.eclipse.cdt.dsf.debug.service.ICachingService; |
| import org.eclipse.cdt.dsf.debug.service.IDisassembly; |
| import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IDisassembly2; |
| import org.eclipse.cdt.dsf.debug.service.IExpressions; |
| import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress; |
| import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMLocation; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; |
| import org.eclipse.cdt.dsf.debug.service.IInstruction; |
| import org.eclipse.cdt.dsf.debug.service.IInstructionWithRawOpcode; |
| import org.eclipse.cdt.dsf.debug.service.IInstructionWithSize; |
| import org.eclipse.cdt.dsf.debug.service.IMixedInstruction; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; |
| import org.eclipse.cdt.dsf.debug.service.ISourceLookup; |
| import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IStack; |
| import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData; |
| import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; |
| import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; |
| import org.eclipse.cdt.dsf.service.DsfServicesTracker; |
| import org.eclipse.cdt.dsf.service.DsfSession; |
| import org.eclipse.cdt.dsf.service.DsfSession.SessionEndedListener; |
| import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Position; |
| |
| public class DisassemblyBackendDsf extends AbstractDisassemblyBackend implements SessionEndedListener { |
| |
| private volatile IExecutionDMContext fTargetContext; |
| private DsfServicesTracker fServicesTracker; |
| private IFrameDMContext fTargetFrameContext; |
| protected IFrameDMData fTargetFrameData; |
| |
| private String fDsfSessionId; |
| |
| /** |
| * Constructor |
| */ |
| public DisassemblyBackendDsf() { |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#init(org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyPartCallback) |
| */ |
| @Override |
| public void init(IDisassemblyPartCallback callback) { |
| super.init(callback); |
| DsfSession.addSessionEndedListener(this); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#dispose() |
| */ |
| @Override |
| public void dispose() { |
| DsfSession.removeSessionEndedListener(this); |
| } |
| |
| public static boolean supportsDebugContext_(IAdaptable context) { |
| IDMVMContext dmvmContext = context.getAdapter(IDMVMContext.class); |
| return dmvmContext != null && hasDisassemblyService(dmvmContext.getDMContext()); |
| } |
| |
| private static boolean hasDisassemblyService(final IDMContext dmContext) { |
| DsfSession session = DsfSession.getSession(dmContext.getSessionId()); |
| if (session == null || !session.isActive()) { |
| return false; |
| } |
| if (session.getExecutor().isInExecutorThread()) { |
| DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId()); |
| IDisassembly disassSvc = tracker.getService(IDisassembly.class); |
| tracker.dispose(); |
| return disassSvc != null; |
| } |
| Query<Boolean> query = new Query<>() { |
| @Override |
| protected void execute(DataRequestMonitor<Boolean> rm) { |
| try { |
| rm.setData(hasDisassemblyService(dmContext)); |
| } finally { |
| rm.done(); |
| } |
| } |
| }; |
| try { |
| session.getExecutor().execute(query); |
| Boolean result = query.get(1, TimeUnit.SECONDS); |
| return result != null && result.booleanValue(); |
| } catch (Exception exc) { |
| // ignored on purpose |
| } |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#supportsDebugContext(org.eclipse.core.runtime.IAdaptable) |
| */ |
| @Override |
| public boolean supportsDebugContext(IAdaptable context) { |
| return supportsDebugContext_(context); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#hasDebugContext() |
| */ |
| @Override |
| public boolean hasDebugContext() { |
| return fTargetContext != null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#setDebugContext(org.eclipse.core.runtime.IAdaptable) |
| */ |
| @Override |
| public SetDebugContextResult setDebugContext(IAdaptable context) { |
| assert supportsDebugContext(context) : "caller should not have invoked us"; //$NON-NLS-1$ |
| IDMVMContext vmContext = context.getAdapter(IDMVMContext.class); |
| IDMContext dmContext = vmContext.getDMContext(); |
| |
| SetDebugContextResult result = new SetDebugContextResult(); |
| |
| String dsfSessionId = dmContext.getSessionId(); |
| |
| if (!dsfSessionId.equals(fDsfSessionId)) { |
| // switch to different session or initiate session |
| if (DEBUG) { |
| System.out.println(MessageFormat.format( |
| "DisassemblyBackendDsf: switch session [{0}<<{1}]. Input context={2}", dsfSessionId, //$NON-NLS-1$ |
| fDsfSessionId, dmContext)); |
| } |
| fTargetContext = null; |
| fTargetFrameContext = null; |
| result.contextChanged = true; |
| |
| if (canDisassembleContext(dmContext)) { |
| if (dmContext instanceof IFrameDMContext) { |
| fTargetFrameContext = (IFrameDMContext) dmContext; |
| } |
| IExecutionDMContext executionContext = DMContexts.getAncestorOfType(dmContext, |
| IExecutionDMContext.class); |
| if (executionContext != null) { |
| fTargetContext = executionContext; |
| } |
| } |
| if (fTargetContext != null) { |
| |
| // remove ourselves as a listener with the previous session (context) |
| if (fDsfSessionId != null) { |
| final DsfSession prevSession = DsfSession.getSession(fDsfSessionId); |
| if (prevSession != null) { |
| try { |
| prevSession.getExecutor().execute(new DsfRunnable() { |
| @Override |
| public void run() { |
| prevSession.removeServiceEventListener(DisassemblyBackendDsf.this); |
| } |
| }); |
| } catch (RejectedExecutionException e) { |
| // Session is shut down. |
| } |
| } |
| } |
| // Ensures the view will display 'No Debug Context' |
| if (fTargetFrameContext != null) { |
| result.sessionId = fDsfSessionId = dsfSessionId; |
| } else { |
| fDsfSessionId = dsfSessionId; |
| result.sessionId = null; |
| } |
| if (fServicesTracker != null) { |
| fServicesTracker.dispose(); |
| } |
| fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), fDsfSessionId); |
| |
| // add ourselves as a listener with the new session (context) |
| final DsfSession newSession = DsfSession.getSession(dsfSessionId); |
| if (newSession != null) { |
| try { |
| newSession.getExecutor().execute(new DsfRunnable() { |
| @Override |
| public void run() { |
| newSession.addServiceEventListener(DisassemblyBackendDsf.this, null); |
| } |
| }); |
| } catch (RejectedExecutionException e) { |
| // Session is shut down. |
| } |
| } |
| } |
| } else if (dmContext instanceof IFrameDMContext) { |
| result.sessionId = fDsfSessionId; |
| // switch to different frame |
| IFrameDMContext frame = (IFrameDMContext) dmContext; |
| IExecutionDMContext newExeDmc = DMContexts.getAncestorOfType(frame, IExecutionDMContext.class); |
| if (newExeDmc != null) { |
| if (fTargetFrameContext != null) { |
| IDisassemblyDMContext newDisDmc = DMContexts.getAncestorOfType(newExeDmc, |
| IDisassemblyDMContext.class); |
| IDisassemblyDMContext oldDisDmc = DMContexts.getAncestorOfType(fTargetContext, |
| IDisassemblyDMContext.class); |
| result.contextChanged = !newDisDmc.equals(oldDisDmc); |
| } else { |
| // If switching from a thread node to a frame node |
| result.contextChanged = true; |
| } |
| fTargetContext = newExeDmc; |
| fTargetFrameContext = frame; |
| if (!result.contextChanged) { |
| fCallback.gotoFrameIfActive(frame.getLevel()); |
| } |
| } else { |
| fTargetContext = null; |
| fTargetFrameContext = null; |
| result.contextChanged = true; |
| } |
| } else if (dmContext instanceof IExecutionDMContext) { |
| // When switching to and between thread and application nodes. |
| result.sessionId = fDsfSessionId; |
| result.contextChanged = false; |
| fTargetContext = (IExecutionDMContext) dmContext; |
| fTargetFrameContext = null; |
| } else if (dmContext.equals(fTargetContext) && canDisassemble()) { |
| result.contextChanged = false; |
| result.sessionId = fDsfSessionId; |
| } else { |
| fTargetContext = null; |
| fTargetFrameContext = null; |
| result.contextChanged = true; |
| } |
| if (DEBUG) { |
| System.out.println(MessageFormat.format( |
| "DisassemblyBackendDsf: switch session done [id={0};context={1};\n\t\t\tframe={2}].\n\t\t\tInput context={3}", //$NON-NLS-1$ |
| fDsfSessionId, fTargetContext, fTargetFrameContext, dmContext)); |
| } |
| return result; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#clearDebugContext() |
| */ |
| @Override |
| public void clearDebugContext() { |
| final DsfSession session = DsfSession.getSession(fDsfSessionId); |
| if (session != null) { |
| try { |
| session.getExecutor().execute(new DsfRunnable() { |
| @Override |
| public void run() { |
| session.removeServiceEventListener(DisassemblyBackendDsf.this); |
| } |
| }); |
| } catch (RejectedExecutionException e) { |
| // Session is shut down. |
| } |
| } |
| fTargetContext = null; |
| if (fServicesTracker != null) { |
| fServicesTracker.dispose(); |
| fServicesTracker = null; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#retrieveFrameAddress(int) |
| */ |
| @Override |
| public void retrieveFrameAddress(final int frame) { |
| final DsfExecutor executor = getSession().getExecutor(); |
| executor.execute(new DsfRunnable() { |
| @Override |
| public void run() { |
| retrieveFrameAddressInSessionThread(frame); |
| } |
| }); |
| } |
| |
| void retrieveFrameAddressInSessionThread(final int frame) { |
| final IStack stack = fServicesTracker.getService(IStack.class); |
| final DsfExecutor executor = getSession().getExecutor(); |
| |
| // Our frame context is currently either un-set or it's set to the frame |
| // our caller is specifying. If un-set, then set it and reinvoke this |
| // method. |
| if (fTargetFrameContext == null) { |
| if (frame == 0) { |
| stack.getTopFrame(fTargetContext, new DataRequestMonitor<IFrameDMContext>(executor, null) { |
| @Override |
| protected void handleCompleted() { |
| fTargetFrameContext = getData(); |
| if (fTargetFrameContext != null) { |
| retrieveFrameAddressInSessionThread(frame); |
| } else { |
| fCallback.setUpdatePending(false); |
| if (canDisassemble()) { |
| final BigInteger address = getLastKnownAddress(); |
| if (address != null && !UNKNOWN_ADDRESS.equals(address)) { |
| fCallback.asyncExec(() -> fCallback.updatePC(address)); |
| } |
| } |
| } |
| } |
| }); |
| } else { |
| // TODO retrieve other stack frame |
| fCallback.setUpdatePending(false); |
| } |
| return; |
| } else if (frame != fTargetFrameContext.getLevel()) { |
| // frame context has changed in the meantime - reinvoke |
| retrieveFrameAddressInSessionThread(fTargetFrameContext.getLevel()); |
| return; |
| } |
| |
| stack.getFrameData(fTargetFrameContext, new DataRequestMonitor<IFrameDMData>(executor, null) { |
| @Override |
| protected void handleCompleted() { |
| fCallback.setUpdatePending(false); |
| IFrameDMData frameData = getData(); |
| fTargetFrameData = frameData; |
| if (!isCanceled() && frameData != null) { |
| final IAddress address = frameData.getAddress(); |
| final BigInteger addressValue = address.getValue(); |
| if (DEBUG) |
| System.out |
| .println("retrieveFrameAddress done " + DisassemblyUtils.getAddressText(addressValue)); //$NON-NLS-1$ |
| fCallback.asyncExec(() -> { |
| if (address.getSize() * 8 != fCallback.getAddressSize()) { |
| fCallback.addressSizeChanged(address.getSize() * 8); |
| } |
| if (frame == 0) { |
| fCallback.updatePC(addressValue); |
| } else { |
| fCallback.gotoFrame(frame, addressValue); |
| } |
| }); |
| } else { |
| final IStatus status = getStatus(); |
| if (status != null && !status.isOK()) { |
| DisassemblyBackendDsf.this.handleError(getStatus()); |
| } |
| } |
| } |
| }); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#isSuspended() |
| */ |
| @Override |
| public boolean isSuspended() { |
| DsfSession session = getSession(); |
| if (session == null || !session.isActive()) { |
| return false; |
| } |
| if (session.getExecutor().isInExecutorThread()) { |
| IRunControl runControl = getRunControl(); |
| if (runControl == null) { |
| return false; |
| } else { |
| return runControl.isSuspended(fTargetContext); |
| } |
| } |
| Query<Boolean> query = new Query<>() { |
| @Override |
| protected void execute(DataRequestMonitor<Boolean> rm) { |
| try { |
| IRunControl runControl = getRunControl(); |
| if (runControl == null) { |
| rm.setData(false); |
| } else { |
| rm.setData(runControl.isSuspended(fTargetContext)); |
| } |
| } finally { |
| rm.done(); |
| } |
| } |
| }; |
| session.getExecutor().execute(query); |
| try { |
| return query.get(); |
| } catch (InterruptedException exc) { |
| } catch (ExecutionException exc) { |
| } |
| |
| return false; |
| } |
| |
| private DsfSession getSession() { |
| return DsfSession.getSession(fDsfSessionId); |
| } |
| |
| private IRunControl getRunControl() { |
| return getService(IRunControl.class); |
| } |
| |
| private <V> V getService(Class<V> serviceClass) { |
| if (fServicesTracker != null) { |
| return fServicesTracker.getService(serviceClass); |
| } |
| return null; |
| } |
| |
| @DsfServiceEventHandler |
| public void handleEvent(IExitedDMEvent event) { |
| if (fTargetContext == null) { |
| return; |
| } |
| final IExecutionDMContext context = event.getDMContext(); |
| if (context.equals(fTargetContext) || DMContexts.isAncestorOf(fTargetContext, context)) { |
| fCallback.asyncExec(() -> fCallback.handleTargetEnded()); |
| } |
| } |
| |
| @DsfServiceEventHandler |
| public void handleEvent(ISuspendedDMEvent event) { |
| if (fTargetContext == null) { |
| return; |
| } |
| final IExecutionDMContext context = event.getDMContext(); |
| if (context.equals(fTargetContext) || DMContexts.isAncestorOf(fTargetContext, context)) { |
| fCallback.handleTargetSuspended(); |
| } |
| } |
| |
| @DsfServiceEventHandler |
| public void handleEvent(IResumedDMEvent event) { |
| if (fTargetContext == null) { |
| return; |
| } |
| final IExecutionDMContext context = event.getDMContext(); |
| if (context.equals(fTargetContext) || DMContexts.isAncestorOf(fTargetContext, context)) { |
| fCallback.handleTargetResumed(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.dsf.service.DsfSession.SessionEndedListener#sessionEnded(org.eclipse.cdt.dsf.service.DsfSession) |
| */ |
| @Override |
| public void sessionEnded(DsfSession session) { |
| if (session.getId().equals(fDsfSessionId)) { |
| clearDebugContext(); |
| fCallback.handleTargetEnded(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#getFrameLevel() |
| */ |
| @Override |
| public int getFrameLevel() { |
| if (fTargetFrameContext != null) { |
| return fTargetFrameContext.getLevel(); |
| } |
| return -1; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#hasFrameContext() |
| */ |
| @Override |
| public boolean hasFrameContext() { |
| return fTargetFrameContext != null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#getFrameFile() |
| */ |
| @Override |
| public String getFrameFile() { |
| return fTargetFrameData.getFile(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#getFrameLine() |
| */ |
| @Override |
| public int getFrameLine() { |
| return fTargetFrameData.getLine(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyBackend#retrieveDisassembly(java.math.BigInteger, java.math.BigInteger, java.lang.String, int, int, boolean, boolean, boolean, int) |
| */ |
| @Override |
| public void retrieveDisassembly(final BigInteger startAddress, BigInteger endAddress, final String file, |
| final int lineNumber, final int lines, final boolean mixed, final boolean showSymbols, |
| final boolean showDisassembly, final int linesHint) { |
| // make sure address range is no less than 32 bytes |
| // this is an attempt to get better a response from the backend (bug 302505) |
| final BigInteger finalEndAddress = startAddress.add(BigInteger.valueOf(32)).max(endAddress); |
| |
| DsfSession session = getSession(); |
| if (session == null) { |
| return; // can happen during session termination |
| } |
| |
| final DsfExecutor executor = session.getExecutor(); |
| final IDisassemblyDMContext context = DMContexts.getAncestorOfType(fTargetContext, IDisassemblyDMContext.class); |
| |
| // align the start address first (bug 328168) |
| executor.execute(() -> alignOpCodeAddress(startAddress, new DataRequestMonitor<BigInteger>(executor, null) { |
| |
| @Override |
| public void handleCompleted() { |
| final BigInteger finalStartAddress = getData(); |
| if (mixed) { |
| final DataRequestMonitor<IMixedInstruction[]> disassemblyRequest = new DataRequestMonitor<>( |
| executor, null) { |
| @Override |
| public void handleCompleted() { |
| final IMixedInstruction[] data = getData(); |
| if (!isCanceled() && data != null) { |
| fCallback.asyncExec(() -> { |
| if (!insertDisassembly(finalStartAddress, finalEndAddress, data, showSymbols, |
| showDisassembly)) { |
| // retry in non-mixed mode |
| fCallback.retrieveDisassembly(finalStartAddress, finalEndAddress, linesHint, |
| false, true); |
| } |
| }); |
| } else { |
| final IStatus status = getStatus(); |
| if (status != null && !status.isOK()) { |
| if (file != null) { |
| fCallback.asyncExec(() -> fCallback.retrieveDisassembly(finalStartAddress, |
| finalEndAddress, linesHint, true, true)); |
| } else { |
| fCallback.asyncExec(() -> fCallback.doScrollLocked( |
| () -> fCallback.insertError(finalStartAddress, status.getMessage()))); |
| } |
| } |
| fCallback.setUpdatePending(false); |
| } |
| } |
| }; |
| if (file != null) { |
| executor.execute(() -> { |
| final IDisassembly disassembly = fServicesTracker.getService(IDisassembly.class); |
| if (disassembly == null) { |
| disassemblyRequest.cancel(); |
| disassemblyRequest.done(); |
| return; |
| } |
| disassembly.getMixedInstructions(context, file, lineNumber, lines * 2, disassemblyRequest); |
| }); |
| } else { |
| executor.execute(() -> { |
| final IDisassembly disassembly = fServicesTracker.getService(IDisassembly.class); |
| if (disassembly == null) { |
| disassemblyRequest.cancel(); |
| disassemblyRequest.done(); |
| return; |
| } |
| disassembly.getMixedInstructions(context, finalStartAddress, finalEndAddress, |
| disassemblyRequest); |
| }); |
| } |
| } else { |
| final DataRequestMonitor<IInstruction[]> disassemblyRequest = new DataRequestMonitor<>(executor, |
| null) { |
| @Override |
| public void handleCompleted() { |
| if (!isCanceled() && getData() != null) { |
| fCallback.asyncExec(() -> { |
| if (!insertDisassembly(finalStartAddress, finalEndAddress, getData(), showSymbols, |
| showDisassembly)) { |
| fCallback.doScrollLocked(() -> fCallback.insertError(finalStartAddress, |
| DisassemblyMessages.DisassemblyBackendDsf_error_UnableToRetrieveData)); |
| } |
| }); |
| } else { |
| final IStatus status = getStatus(); |
| if (status != null && !status.isOK()) { |
| fCallback.asyncExec(() -> fCallback.doScrollLocked( |
| () -> fCallback.insertError(finalStartAddress, status.getMessage()))); |
| } |
| fCallback.setUpdatePending(false); |
| } |
| } |
| }; |
| executor.execute(() -> { |
| final IDisassembly disassembly = fServicesTracker.getService(IDisassembly.class); |
| if (disassembly == null) { |
| disassemblyRequest.cancel(); |
| disassemblyRequest.done(); |
| return; |
| } |
| disassembly.getInstructions(context, finalStartAddress, finalEndAddress, disassemblyRequest); |
| }); |
| } |
| } |
| })); |
| } |
| |
| private boolean insertDisassembly(BigInteger startAddress, BigInteger endAddress, IInstruction[] instructions, |
| boolean showSymbols, boolean showDisassembly) { |
| if (!fCallback.hasViewer() || fDsfSessionId == null || fTargetContext == null) { |
| if (DEBUG) { |
| System.out.println(MessageFormat.format( |
| "insertDisassembly ignored at {0} due to missing context: [fDsfSessionId={1};fTargetContext={2}]", //$NON-NLS-1$ |
| DisassemblyUtils.getAddressText(startAddress), fDsfSessionId, fTargetContext)); |
| } |
| if (fTargetContext == null) { |
| fCallback.setUpdatePending(false); |
| } |
| // return true to avoid a retry |
| return true; |
| } |
| if (DEBUG) |
| System.out.println("insertDisassembly " + DisassemblyUtils.getAddressText(startAddress)); //$NON-NLS-1$ |
| assert fCallback.getUpdatePending(); |
| if (!fCallback.getUpdatePending()) { |
| // safe-guard in case something weird is going on |
| // return true to avoid a retry |
| return true; |
| } |
| |
| boolean insertedAnyAddress = false; |
| |
| try { |
| fCallback.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) { |
| startAddress = address; |
| fCallback.setGotoAddressPending(address); |
| } |
| if (p == null || !p.containsAddress(address)) { |
| p = fCallback.getPositionOfAddress(address); |
| } |
| if (p instanceof ErrorPosition && p.fValid) { |
| p.fValid = false; |
| fCallback.getDocument().addInvalidAddressRange(p); |
| } else if (p == null || address.compareTo(endAddress) > 0) { |
| if (DEBUG) |
| System.out.println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$ |
| return insertedAnyAddress; |
| } else if (p.fValid) { |
| if (DEBUG) |
| System.out.println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$ |
| if (!p.fAddressOffset.equals(address)) { |
| // override probably unaligned disassembly |
| p.fValid = false; |
| fCallback.getDocument().addInvalidAddressRange(p); |
| } else { |
| continue; |
| } |
| } |
| boolean hasSource = false; |
| String compilationPath = null; |
| // insert symbol label |
| final String functionName = instruction.getFuntionName(); |
| if (functionName != null && !functionName.isEmpty() && instruction.getOffset() == 0) { |
| p = fCallback.getDocument().insertLabel(p, address, functionName, |
| showSymbols && (!hasSource || showDisassembly)); |
| } |
| // determine instruction byte length |
| BigInteger instrLength = null; |
| if (instruction instanceof IInstructionWithSize |
| && ((IInstructionWithSize) instruction).getSize() != null) { |
| instrLength = new BigInteger(((IInstructionWithSize) instruction).getSize().toString()); |
| } else { |
| if (j < instructions.length - 1) { |
| instrLength = instructions[j + 1].getAdress().subtract(instruction.getAdress()).abs(); |
| } |
| if (instrLength == null) { |
| // cannot determine length of last instruction |
| break; |
| } |
| } |
| final String functionOffset; // Renamed from opCode to avoid confusion |
| // insert function name+offset instead of opcode bytes |
| if (functionName != null && !functionName.isEmpty()) { |
| functionOffset = functionName + '+' + instruction.getOffset(); |
| } else { |
| functionOffset = ""; //$NON-NLS-1$ |
| } |
| |
| String opcode = null; |
| // Get raw Opcodes if available |
| if (instruction instanceof IInstructionWithRawOpcode) { |
| opcode = ((IInstructionWithRawOpcode) instruction).getRawOpcode(); |
| } |
| |
| p = fCallback.getDocument().insertDisassemblyLine(p, address, instrLength.intValue(), functionOffset, |
| opcode, instruction.getInstruction(), compilationPath, -1); |
| if (p == null) { |
| break; |
| } |
| insertedAnyAddress = true; |
| } |
| } catch (BadLocationException e) { |
| // should not happen |
| DisassemblyUtils.internalError(e); |
| } finally { |
| fCallback.setUpdatePending(false); |
| if (insertedAnyAddress) { |
| fCallback.updateInvalidSource(); |
| fCallback.unlockScroller(); |
| fCallback.doPending(); |
| fCallback.updateVisibleArea(); |
| } else { |
| fCallback.unlockScroller(); |
| } |
| } |
| return insertedAnyAddress; |
| } |
| |
| /** |
| * @param startAddress |
| * an address the caller is hoping will be covered by this |
| * insertion. I.e., [mixedInstructions] may or may not contain |
| * that address; the caller wants to know if it does, and so we |
| * indicate that via our return value. Can be null to indicate n/a, |
| * in which case we return true as long as any instruction was inserted |
| * as long as any instruction was inserted |
| * @param endAddress |
| * cut-off address. Any elements in [mixedInstructions] that |
| * extend beyond this address are ignored. |
| * @param mixedInstructions |
| * @param showSymbols |
| * @param showDisassembly |
| * @return whether [startAddress] was inserted |
| */ |
| private boolean insertDisassembly(BigInteger startAddress, BigInteger endAddress, |
| IMixedInstruction[] mixedInstructions, boolean showSymbols, boolean showDisassembly) { |
| if (!fCallback.hasViewer() || fDsfSessionId == null || fTargetContext == null) { |
| if (DEBUG) { |
| System.out.println(MessageFormat.format( |
| "insertDisassembly ignored at {0} : missing context: [fDsfSessionId={1};fTargetContext={2}]", //$NON-NLS-1$ |
| DisassemblyUtils.getAddressText(startAddress), fDsfSessionId, fTargetContext)); |
| } |
| if (fTargetContext == null) { |
| fCallback.setUpdatePending(false); |
| } |
| // return true to avoid a retry |
| return true; |
| } |
| if (DEBUG) |
| System.out.println("insertDisassembly " + DisassemblyUtils.getAddressText(startAddress)); //$NON-NLS-1$ |
| boolean updatePending = fCallback.getUpdatePending(); |
| assert updatePending; |
| if (!updatePending) { |
| // safe-guard in case something weird is going on |
| // return true to avoid a retry |
| return true; |
| } |
| |
| boolean insertedAnyAddress = false; |
| try { |
| fCallback.lockScroller(); |
| |
| AddressRangePosition p = null; |
| for (int i = 0; i < mixedInstructions.length; ++i) { |
| IMixedInstruction mixedInstruction = mixedInstructions[i]; |
| final String file = mixedInstruction.getFileName(); |
| 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 = address; |
| fCallback.setGotoAddressPending(address); |
| } |
| if (p == null || !p.containsAddress(address)) { |
| p = fCallback.getPositionOfAddress(address); |
| } |
| if (p instanceof ErrorPosition && p.fValid) { |
| p.fValid = false; |
| fCallback.getDocument().addInvalidAddressRange(p); |
| } else if (p == null || address.compareTo(endAddress) > 0) { |
| if (DEBUG) |
| System.out |
| .println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$ |
| return insertedAnyAddress; |
| } else if (p.fValid) { |
| if (DEBUG) |
| System.out |
| .println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$ |
| if (!p.fAddressOffset.equals(address)) { |
| // override probably unaligned disassembly |
| p.fValid = false; |
| fCallback.getDocument().addInvalidAddressRange(p); |
| } else { |
| continue; |
| } |
| } |
| boolean hasSource = false; |
| if (file != null && lineNumber >= 0) { |
| p = fCallback.insertSource(p, address, file, lineNumber); |
| hasSource = fCallback.getStorageForFile(file) != null; |
| } |
| // insert symbol label |
| final String functionName = instruction.getFuntionName(); |
| if (functionName != null && !functionName.isEmpty() && instruction.getOffset() == 0) { |
| p = fCallback.getDocument().insertLabel(p, address, functionName, |
| showSymbols && (!hasSource || showDisassembly)); |
| } |
| // determine instruction byte length |
| BigInteger instrLength = null; |
| if (instruction instanceof IInstructionWithSize |
| && ((IInstructionWithSize) instruction).getSize() != null) { |
| instrLength = new BigInteger(((IInstructionWithSize) instruction).getSize().toString()); |
| } else { |
| 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; |
| } |
| } |
| if (instrLength == null) { |
| // cannot determine length of last instruction |
| break; |
| } |
| } |
| final String funcOffset; |
| // insert function name+offset instead of opcode bytes |
| if (functionName != null && !functionName.isEmpty()) { |
| funcOffset = functionName + '+' + instruction.getOffset(); |
| } else { |
| funcOffset = ""; //$NON-NLS-1$ |
| } |
| |
| String opcode = null; |
| if (instruction instanceof IInstructionWithRawOpcode) { |
| opcode = ((IInstructionWithRawOpcode) instruction).getRawOpcode(); |
| } |
| |
| p = fCallback.getDocument().insertDisassemblyLine(p, address, instrLength.intValue(), funcOffset, |
| opcode, instruction.getInstruction(), file, lineNumber); |
| if (p == null) { |
| break; |
| } |
| insertedAnyAddress = true; |
| } |
| } |
| |
| } catch (BadLocationException e) { |
| // should not happen |
| DisassemblyUtils.internalError(e); |
| } finally { |
| fCallback.setUpdatePending(false); |
| if (insertedAnyAddress) { |
| fCallback.updateInvalidSource(); |
| fCallback.unlockScroller(); |
| fCallback.doPending(); |
| fCallback.updateVisibleArea(); |
| } else { |
| fCallback.unlockScroller(); |
| } |
| } |
| return insertedAnyAddress; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#insertSource(org.eclipse.jface.text.Position, java.math.BigInteger, java.lang.String, int) |
| */ |
| @Override |
| public Object insertSource(Position pos, BigInteger address, final String file, int lineNumber) { |
| Object sourceElement = null; |
| final ISourceLookupDMContext ctx = DMContexts.getAncestorOfType(fTargetContext, ISourceLookupDMContext.class); |
| final DsfExecutor executor = getSession().getExecutor(); |
| Query<Object> query = new Query<>() { |
| @Override |
| protected void execute(final DataRequestMonitor<Object> rm) { |
| final DataRequestMonitor<Object> request = new DataRequestMonitor<>(executor, rm) { |
| @Override |
| protected void handleSuccess() { |
| rm.setData(getData()); |
| rm.done(); |
| } |
| }; |
| final ISourceLookup lookup = getService(ISourceLookup.class); |
| lookup.getSource(ctx, file, request); |
| } |
| }; |
| try { |
| getSession().getExecutor().execute(query); |
| sourceElement = query.get(); |
| } catch (InterruptedException exc) { |
| DisassemblyUtils.internalError(exc); |
| } catch (ExecutionException exc) { |
| DisassemblyUtils.internalError(exc); |
| } |
| return sourceElement; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#gotoSymbol(java.lang.String) |
| */ |
| @Override |
| public void gotoSymbol(final String symbol) { |
| if (!hasFrameContext()) { |
| return; |
| } |
| evaluateAddressExpression(symbol, false, new DataRequestMonitor<BigInteger>(getSession().getExecutor(), null) { |
| @Override |
| protected void handleSuccess() { |
| final BigInteger address = getData(); |
| if (address != null) { |
| fCallback.asyncExec(() -> fCallback.gotoAddress(address)); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| public BigInteger evaluateAddressExpression(final String symbol, final boolean suppressError) { |
| // Without a suspended context, using the expressions service is pointless. |
| if (!hasFrameContext()) { |
| return null; |
| } |
| Query<BigInteger> query = new Query<>() { |
| @Override |
| protected void execute(DataRequestMonitor<BigInteger> rm) { |
| evaluateAddressExpression(symbol, suppressError, rm); |
| } |
| }; |
| getSession().getExecutor().execute(query); |
| try { |
| return query.get(); |
| } catch (Exception e) { |
| return null; |
| } |
| } |
| |
| private void evaluateAddressExpression(final String symbol, final boolean suppressError, |
| final DataRequestMonitor<BigInteger> rm) { |
| final IExpressions expressions = getService(IExpressions.class); |
| if (expressions == null) { |
| rm.setStatus( |
| new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| final IExpressionDMContext exprDmc = expressions.createExpression(fTargetContext, symbol); |
| // first, try to get l-value address |
| expressions.getExpressionAddressData(exprDmc, |
| new DataRequestMonitor<IExpressionDMAddress>(getSession().getExecutor(), null) { |
| @Override |
| protected void handleSuccess() { |
| IExpressionDMAddress data = getData(); |
| final IAddress address = data.getAddress(); |
| if (address != null && address != IExpressionDMLocation.INVALID_ADDRESS) { |
| final BigInteger addressValue = address.getValue(); |
| fCallback.asyncExec(() -> fCallback.gotoAddress(addressValue)); |
| rm.setData(addressValue); |
| rm.done(); |
| } else { |
| handleError(); |
| } |
| } |
| |
| @Override |
| protected void handleError() { |
| // not an l-value, evaluate expression |
| final FormattedValueDMContext valueDmc = expressions.getFormattedValueContext(exprDmc, |
| IFormattedValues.HEX_FORMAT); |
| expressions.getFormattedExpressionValue(valueDmc, |
| new DataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), null) { |
| @Override |
| protected void handleSuccess() { |
| FormattedValueDMData data = getData(); |
| String value = data.getFormattedValue(); |
| BigInteger address = null; |
| try { |
| address = DisassemblyUtils.decodeAddress(value); |
| } catch (final Exception e) { |
| // "value" can be empty i.e *fooX, where fooX is a variable. |
| // Not sure if this is a bug or not. So, fail the request instead. |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, |
| IDsfStatusConstants.REQUEST_FAILED, "", null)); //$NON-NLS-1$ |
| |
| if (!suppressError) { |
| DisassemblyBackendDsf.this.handleError(new Status(IStatus.ERROR, |
| DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, |
| DisassemblyMessages.Disassembly_log_error_expression_eval + " (" //$NON-NLS-1$ |
| + e.getMessage() + ")", //$NON-NLS-1$ |
| null)); |
| } |
| } |
| rm.setData(address); |
| rm.done(); |
| } |
| |
| @Override |
| protected void handleError() { |
| if (!suppressError) { |
| DisassemblyBackendDsf.this.handleError(getStatus()); |
| } |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, |
| IDsfStatusConstants.REQUEST_FAILED, "", null)); //$NON-NLS-1$ |
| rm.done(); |
| } |
| }); |
| } |
| }); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#retrieveDisassembly(java.lang.String, int, java.math.BigInteger, boolean, boolean, boolean) |
| */ |
| @Override |
| public void retrieveDisassembly(final String file, final int lines, final BigInteger endAddress, boolean mixed, |
| final boolean showSymbols, final boolean showDisassembly) { |
| String debuggerPath = file; |
| // try reverse lookup |
| final ISourceLookupDMContext ctx = DMContexts.getAncestorOfType(fTargetContext, ISourceLookupDMContext.class); |
| final DsfExecutor executor = getSession().getExecutor(); |
| Query<String> query = new Query<>() { |
| @Override |
| protected void execute(final DataRequestMonitor<String> rm) { |
| final DataRequestMonitor<String> request = new DataRequestMonitor<>(executor, rm) { |
| @Override |
| protected void handleSuccess() { |
| rm.setData(getData()); |
| rm.done(); |
| } |
| }; |
| final ISourceLookup lookup = getService(ISourceLookup.class); |
| lookup.getDebuggerPath(ctx, file, request); |
| } |
| }; |
| try { |
| getSession().getExecutor().execute(query); |
| debuggerPath = query.get(); |
| } catch (InterruptedException exc) { |
| internalError(exc); |
| } catch (ExecutionException exc) { |
| internalError(exc); |
| } |
| |
| final IDisassemblyDMContext context = DMContexts.getAncestorOfType(fTargetContext, IDisassemblyDMContext.class); |
| |
| final String finalFile = debuggerPath; |
| final DataRequestMonitor<IMixedInstruction[]> disassemblyRequest = new DataRequestMonitor<>(executor, null) { |
| @Override |
| public void handleCompleted() { |
| final IMixedInstruction[] data = getData(); |
| if (!isCanceled() && data != null) { |
| fCallback.asyncExec(() -> { |
| if (!insertDisassembly(null, endAddress, data, showSymbols, showDisassembly)) { |
| // retry in non-mixed mode |
| retrieveDisassembly(file, lines, endAddress, false, showSymbols, showDisassembly); |
| } |
| }); |
| } else { |
| final IStatus status = getStatus(); |
| if (status != null && !status.isOK()) { |
| DisassemblyBackendDsf.this.handleError(getStatus()); |
| } |
| fCallback.setUpdatePending(false); |
| } |
| } |
| }; |
| assert !fCallback.getUpdatePending(); |
| fCallback.setUpdatePending(true); |
| executor.execute(() -> { |
| final IDisassembly disassembly = fServicesTracker.getService(IDisassembly.class); |
| if (disassembly == null) { |
| disassemblyRequest.cancel(); |
| disassemblyRequest.done(); |
| return; |
| } |
| disassembly.getMixedInstructions(context, finalFile, 1, lines, disassemblyRequest); |
| }); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#evaluateExpression(java.lang.String) |
| */ |
| @Override |
| public String evaluateExpression(final String expression) { |
| if (fTargetFrameContext == null) { |
| return null; |
| } |
| final DsfExecutor executor = DsfSession.getSession(fDsfSessionId).getExecutor(); |
| Query<FormattedValueDMData> query = new Query<>() { |
| @Override |
| protected void execute(final DataRequestMonitor<FormattedValueDMData> rm) { |
| IExecutionDMContext exeCtx = DMContexts.getAncestorOfType(fTargetFrameContext, |
| IExecutionDMContext.class); |
| final IRunControl rc = getService(IRunControl.class); |
| if (rc == null || !rc.isSuspended(exeCtx)) { |
| rm.done(); |
| return; |
| } |
| final IExpressions expressions = getService(IExpressions.class); |
| if (expressions == null) { |
| rm.done(); |
| return; |
| } |
| IExpressionDMContext exprDmc = expressions.createExpression(fTargetFrameContext, expression); |
| final FormattedValueDMContext valueDmc = expressions.getFormattedValueContext(exprDmc, |
| IFormattedValues.NATURAL_FORMAT); |
| expressions.getFormattedExpressionValue(valueDmc, |
| new DataRequestMonitor<FormattedValueDMData>(executor, rm) { |
| @Override |
| protected void handleSuccess() { |
| FormattedValueDMData data = getData(); |
| rm.setData(data); |
| rm.done(); |
| } |
| }); |
| } |
| }; |
| |
| executor.execute(query); |
| FormattedValueDMData data = null; |
| try { |
| data = query.get(); |
| } catch (InterruptedException exc) { |
| } catch (ExecutionException exc) { |
| } |
| if (data != null) { |
| return data.getFormattedValue(); |
| } |
| return null; |
| |
| } |
| |
| @Override |
| public String evaluateRegister(final String potentialRegisterName) { |
| if (fTargetFrameContext == null) { |
| return null; |
| } |
| final DsfExecutor executor = DsfSession.getSession(fDsfSessionId).getExecutor(); |
| |
| Query<FormattedValueDMData> query = new Query<>() { |
| @Override |
| protected void execute(final DataRequestMonitor<FormattedValueDMData> rm) { |
| IExecutionDMContext exeCtx = DMContexts.getAncestorOfType(fTargetFrameContext, |
| IExecutionDMContext.class); |
| final IRunControl rc = getService(IRunControl.class); |
| if (rc == null || !rc.isSuspended(exeCtx)) { |
| rm.done(); |
| return; |
| } |
| final IRegisters registersService = getService(IRegisters.class); |
| if (registersService == null) { |
| rm.done(); |
| return; |
| } |
| |
| // find registers for current frame context |
| registersService.findRegister(fTargetFrameContext, potentialRegisterName, |
| new DataRequestMonitor<IRegisterDMContext>(executor, rm) { |
| @Override |
| protected void handleSuccess() { |
| // handle to the register we're looking-for |
| final IRegisterDMContext theOne = getData(); |
| |
| FormattedValueDMContext fmtCtx = registersService.getFormattedValueContext(theOne, |
| IFormattedValues.HEX_FORMAT); |
| registersService.getFormattedExpressionValue(fmtCtx, |
| new DataRequestMonitor<FormattedValueDMData>(executor, rm) { |
| @Override |
| protected void handleSuccess() { |
| rm.done(getData()); |
| } |
| }); |
| } |
| }); |
| } |
| }; |
| |
| executor.execute(query); |
| String returnValue = null; |
| try { |
| // set a query timeout, to help avoid potential deadlock |
| FormattedValueDMData data = query.get(500, TimeUnit.MILLISECONDS); |
| if (data != null) { |
| returnValue = data.getFormattedValue(); |
| } |
| } catch (InterruptedException exc) { |
| } catch (ExecutionException exc) { |
| } catch (TimeoutException exc) { |
| } |
| |
| return returnValue; |
| } |
| |
| /** |
| * Align the opCode of an address. |
| * |
| * @param addr the address |
| * @param rm the data request monitor |
| */ |
| @ConfinedToDsfExecutor("getSession().getExecutor()") |
| void alignOpCodeAddress(final BigInteger addr, final DataRequestMonitor<BigInteger> rm) { |
| IDisassembly2 disassembly = getService(IDisassembly2.class); |
| if (disassembly == null) { |
| rm.setData(addr); |
| rm.done(); |
| return; |
| } |
| |
| final IDisassemblyDMContext context = DMContexts.getAncestorOfType(fTargetContext, IDisassemblyDMContext.class); |
| disassembly.alignOpCodeAddress(context, addr, new ImmediateDataRequestMonitor<BigInteger>(rm) { |
| @Override |
| protected void handleFailure() { |
| rm.setData(addr); |
| rm.done(); |
| } |
| |
| @Override |
| protected void handleSuccess() { |
| rm.setData(getData()); |
| rm.done(); |
| } |
| }); |
| } |
| |
| /** |
| * Sub classes can override this method to allow disassemble for other DMContext. |
| * @param context |
| * @return |
| */ |
| protected boolean canDisassembleContext(IDMContext context) { |
| return DMContexts.getAncestorOfType(context, IExecutionDMContext.class) != null; |
| } |
| |
| /** |
| * Returns the target context for the current selected debug context. |
| * @return |
| */ |
| protected IExecutionDMContext getExecutionDMContext() { |
| return fTargetContext; |
| } |
| |
| @Override |
| protected void handleError(IStatus status) { |
| DsfUIPlugin.log(status); |
| } |
| |
| @Override |
| public void clearCaches() { |
| final DsfExecutor executor = getSession().getExecutor(); |
| executor.execute(new DsfRunnable() { |
| @Override |
| public void run() { |
| List.of(IStack.class, IDisassembly.class, IExpressions.class, IRunControl.class, IRegisters.class, |
| ISourceLookup.class).forEach((clazz) -> { |
| Object o = getService(clazz); |
| if (o instanceof ICachingService) { |
| ICachingService cs = (ICachingService) o; |
| cs.flushCache(getExecutionDMContext()); |
| } |
| }); |
| } |
| }); |
| |
| } |
| } |