diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java index 9fabdab6f67..b114acad5ce 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java @@ -58,6 +58,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens private BigInteger fBlockAddress; private int fLength; + private int fWordSize; private MemoryByte[] fBlock; private ArrayList fConnections = new ArrayList(); @@ -72,9 +73,10 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @param modelId - * @param expression - the displayed expression in the UI * @param address - the actual memory block start address - * @param length - the memory block length (could be 0) + * @param word_size - the number of bytes per address + * @param length - the requested block length (could be 0) */ - DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, String modelId, String expression, BigInteger address, long length) { + DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, String modelId, String expression, BigInteger address, int word_size, long length) { fLaunch = retrieval.getLaunch(); fDebugTarget = retrieval.getDebugTarget(); @@ -85,6 +87,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens // Current block information fBlockAddress = address; + fWordSize = word_size; fLength = (int) length; fBlock = null; @@ -413,7 +416,6 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens // For the IAddress interface final Addr64 address = new Addr64(bigAddress); - final int word_size = 1; // Use a Query to synchronize the downstream calls Query query = new Query() { @@ -423,7 +425,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens if (memoryService != null) { // Go for it memoryService.getMemory( - fRetrieval.getContext(), address, 0, word_size, (int) length, + fRetrieval.getContext(), address, 0, fWordSize, (int) length, new DataRequestMonitor(fRetrieval.getExecutor(), drm) { @Override protected void handleOK() { @@ -460,9 +462,8 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens // For the IAddress interface final Addr64 address = new Addr64(fBaseAddress); - final int word_size = 1; - // Use a Query to synchronise the downstream calls + // Use a Query to synchronize the downstream calls Query query = new Query() { @Override protected void execute(final DataRequestMonitor drm) { @@ -470,7 +471,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens if (memoryService != null) { // Go for it memoryService.setMemory( - fRetrieval.getContext(), address, offset, word_size, bytes.length, bytes, + fRetrieval.getContext(), address, offset, fWordSize, bytes.length, bytes, new RequestMonitor(fRetrieval.getExecutor(), null)); } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java index 5095a8c35ca..bd0c65652f2 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java @@ -15,8 +15,11 @@ package org.eclipse.dd.dsf.debug.model; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ExecutionException; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.PlatformObject; @@ -36,8 +39,12 @@ import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext; import org.eclipse.dd.dsf.service.DsfServices; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.dsf.service.DsfSession.SessionEndedListener; import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IMemoryBlockExtension; @@ -45,6 +52,10 @@ import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.util.tracker.ServiceTracker; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; /** * Implementation of memory access API of the Eclipse standard debug model. @@ -62,15 +73,24 @@ import org.osgi.util.tracker.ServiceTracker; * code will still be functional after some trivial adjustments. * */ -public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBlockRetrievalExtension +public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBlockRetrievalExtension, SessionEndedListener { - private final String fModelId; - private final DsfSession fSession; - private final DsfExecutor fExecutor; - private IMemoryDMContext fContext; - private final ServiceTracker fMemoryServiceTracker; - private final ServiceTracker fExpressionServiceTracker; + private final String fModelId; + private final DsfSession fSession; + private final DsfExecutor fExecutor; + private final IMemoryDMContext fContext; + private final String fContextString; + private final ServiceTracker fMemoryServiceTracker; + private final ServiceTracker fExpressionServiceTracker; + private final ILaunchConfiguration fLaunchConfig; + private final ILaunch fLaunch; + private final IDebugTarget fDebugTarget; + private final boolean fSupportsValueModification; + private final boolean fSupportBaseAddressModification; + private final int fAddressSize; + private final int fWordSize; // Number of bytes per address + /** * Constructor * @@ -78,11 +98,23 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl * @param dmc * @throws DebugException */ - public DsfMemoryBlockRetrieval(String modelId, IMemoryDMContext dmc) throws DebugException { + public DsfMemoryBlockRetrieval(String modelId, ILaunchConfiguration config, IMemoryDMContext dmc) throws DebugException { - fModelId = modelId; - fContext = dmc; - fSession = DsfSession.getSession(fContext.getSessionId()); + // DSF stuff + fModelId = modelId; + fContext = dmc; + + // FIXME: Currently memory contexts are differentiated by sessionID + // so there is no way to guarantee the memory blocks will be reinstated + // in the correct memory space. + // Need a way to create deterministically the context ID from a unique + // target, ideally from the launch configuration (or derived from it). + // For the time being, just put some constant. This will work until we + // support multiple targets in the same launch. + // fContextString = fContext.toString(); + fContextString = "Context string"; //$NON-NLS-1$ + + fSession = DsfSession.getSession(fContext.getSessionId()); if (fSession == null) { throw new IllegalArgumentException( "Session for context " + fContext + " is not active"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -94,7 +126,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl // amalgamated one because it is less error prone (and we are lazy). // Create a tracker for the MemoryService - String memoryServiceFilter = DsfServices.createServiceFilter( IMemory.class, dmc.getSessionId() ); + String memoryServiceFilter = DsfServices.createServiceFilter(IMemory.class, dmc.getSessionId()); try { fMemoryServiceTracker = new ServiceTracker( @@ -124,11 +156,160 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl "Error creating service filter.", e)); //$NON-NLS-1$ } fExpressionServiceTracker.open(); + + // Launch configuration information + fLaunchConfig = config; + fLaunch = null; + fDebugTarget = null; + fAddressSize = 4; // Get this from the launch configuration + fWordSize = 1; // Get this from the launch configuration + fSupportsValueModification = true; // Get this from the launch configuration + fSupportBaseAddressModification = false; // Get this from the launch configuration + + // So we are notified on exit and can save the memory blocks + DsfSession.addSessionEndedListener(this); } - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + // Memory monitors persistence + /////////////////////////////////////////////////////////////////////////// + + /* + * In the launch configuration file, the memory block entry is structured + * as follows (note: this differs from CDI): + * + * + * + * + * + * ... + * + * ... + * + * ... + * " + * /> + */ + + //------------------------------------------------------------------------- + // Memory blocks memento tags + //------------------------------------------------------------------------- + + // These 2 really belong in the DSF launch configuration class... + private static final String DSF_LAUNCH_ID = "org.eclipse.dsf.launch"; //$NON-NLS-1$ + private static final String ATTR_DEBUGGER_MEMORY_BLOCKS = DSF_LAUNCH_ID + ".MEMORY_BLOCKS"; //$NON-NLS-1$ + + private static final String MEMORY_BLOCK_EXPRESSION_LIST = "memoryBlockExpressionList"; //$NON-NLS-1$ + private static final String ATTR_EXPRESSION_LIST_CONTEXT = "context"; //$NON-NLS-1$ + private static final String MEMORY_BLOCK_EXPRESSION = "memoryBlockExpression"; //$NON-NLS-1$ + private static final String ATTR_MEMORY_BLOCK_EXPR_LABEL = "label"; //$NON-NLS-1$ + private static final String ATTR_MEMORY_BLOCK_EXPR_ADDRESS = "address"; //$NON-NLS-1$ + + //------------------------------------------------------------------------- + // Install persisted memory monitors + //------------------------------------------------------------------------- + + /** + * Restore the memory monitors from the memento in the launch configuration + */ + public void initialize() { + try { + final String memento = fLaunchConfig.getAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, ""); //$NON-NLS-1$ + if (memento != null && memento.trim().length() != 0) { + // Submit the runnable to install the monitors on dispatch thread. + getExecutor().submit(new Runnable() { + public void run() { + try { + createBlocksFromConfiguration(memento); + } catch (CoreException e) { + DsfDebugPlugin.getDefault().getLog().log(e.getStatus()); + } + } + }); + } + } catch (CoreException e) { + DsfDebugPlugin.getDefault().getLog().log(e.getStatus()); + } + } + + private void createBlocksFromConfiguration(String memento) throws CoreException { + + // Parse the memento and validate its type + Element root = DebugPlugin.parseDocument(memento); + if (!root.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION_LIST)) { + IStatus status = new Status(IStatus.ERROR, DsfDebugPlugin.PLUGIN_ID, DebugPlugin.INTERNAL_ERROR, + "Memory monitor initialization: invalid memento", null);//$NON-NLS-1$ + throw new CoreException(status); + } + + // Process the block list specific to this memory context + // FIXME: We only process the first entry... + if (root.getAttribute(ATTR_EXPRESSION_LIST_CONTEXT).equals(fContextString)) { + List blocks = new ArrayList(); + NodeList expressionList = root.getChildNodes(); + int length = expressionList.getLength(); + for (int i = 0; i < length; ++i) { + Node node = expressionList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element entry = (Element) node; + if (entry.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION)) { + String label = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL); + String address = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS); + BigInteger blockAddress = new BigInteger(address); + DsfMemoryBlock block = new DsfMemoryBlock(this, fModelId, label, blockAddress, fWordSize, 0); + blocks.add(block); + } + } + } + DebugPlugin.getDefault().getMemoryBlockManager().addMemoryBlocks( blocks.toArray(new IMemoryBlock[blocks.size()])); + } + } + + /** + * On session exit, save the memory blocks in the launch configuration + */ + public void sessionEnded(DsfSession session) { + DsfSession.removeSessionEndedListener(this); + saveMemoryBlocks(); + } + + // FIXME: Each retrieval overwrites the previous one :-( + // FIXME: Racing condition :-( - synchronize on launch config enough? + // FIXME: Make it a Job? + public void saveMemoryBlocks() { + try { + ILaunchConfigurationWorkingCopy wc = fLaunchConfig.getWorkingCopy(); + wc.setAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, getMemento()); + wc.doSave(); + } + catch( CoreException e ) { + DsfDebugPlugin.getDefault().getLog().log(e.getStatus()); + } + } + + public String getMemento() throws CoreException { + IMemoryBlock[] blocks = DebugPlugin.getDefault().getMemoryBlockManager().getMemoryBlocks(this); + Document document = DebugPlugin.newDocument(); + Element expressionList = document.createElement(MEMORY_BLOCK_EXPRESSION_LIST); + expressionList.setAttribute(ATTR_EXPRESSION_LIST_CONTEXT, fContextString); + for (IMemoryBlock block : blocks) { + if (block instanceof IMemoryBlockExtension) { + IMemoryBlockExtension memoryBlock = (IMemoryBlockExtension) block; + Element expression = document.createElement(MEMORY_BLOCK_EXPRESSION); + expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL, memoryBlock.getExpression()); + expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS, memoryBlock.getBigBaseAddress().toString()); + expressionList.appendChild(expression); + } + } + document.appendChild(expressionList); + return DebugPlugin.serializeDocument(document); + } + + /////////////////////////////////////////////////////////////////////////// // Accessors - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// public DsfSession getSession() { return fSession; @@ -146,38 +327,37 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl return fMemoryServiceTracker; } - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// // Launch/Target specific information - // To be completed - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// public ILaunch getLaunch() { - return null; + return fLaunch; } public IDebugTarget getDebugTarget() { - return null; + return fDebugTarget; } public int getAddressSize() { - return 4; + return fAddressSize; } public int getAddressableSize() { - return 1; + return fWordSize; } public boolean supportsValueModification() { - return true; + return fSupportsValueModification; } public boolean supportBaseAddressModification() { - return false; + return fSupportBaseAddressModification; } - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// // IMemoryBlockRetrieval - obsoleted by IMemoryBlockRetrievalExtension - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// /* * (non-Javadoc) @@ -198,12 +378,12 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl // The expression to display in the rendering tab (in hex by convention) // Put here for the sake of completeness (not used with IMemoryBlockExtension) String expression = "0x" + Long.toHexString(startAddress); //$NON-NLS-1$ - return new DsfMemoryBlock(this, fModelId, expression, BigInteger.valueOf(startAddress), length); + return new DsfMemoryBlock(this, fModelId, expression, BigInteger.valueOf(startAddress), fWordSize, length); } - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// // IMemoryBlockRetrievalExtension - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// /* * (non-Javadoc) @@ -277,12 +457,12 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl * the memory request cache should save the day. */ - return new DsfMemoryBlock(this, fModelId, expression, blockAddress, 0); + return new DsfMemoryBlock(this, fModelId, expression, blockAddress, fWordSize, 0); } - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// // Helper functions - // //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// private BigInteger resolveMemoryAddress(final IDMContext idmContext, final String expression) throws DebugException { diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IDisassembly.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IDisassembly.java new file mode 100644 index 00000000000..aa90f393975 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IDisassembly.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.dsf.debug.service; + +import java.math.BigInteger; + +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.service.IDsfService; + +/** + * Disassembly service interface + */ +public interface IDisassembly extends IDsfService { + + public interface IDisassemblyDMContext extends IDMContext {} + + /** + * Gets the disassembled code from an address range. + * If [startAddress] == null, disassemble from the instruction pointer. + * + * @param context Context of the disassembly code + * @param startAddress Beginning address + * @param endAddress End address + * @param drm Disassembled code + */ + public void getInstructions( + IDisassemblyDMContext context, + BigInteger startAddress, + BigInteger endAddress, + DataRequestMonitor drm); + + /** + * Gets the disassembled code from a file location. + * If [lines] == -1, the whole function is disassembled. + * + * @param context Context of the disassembly code + * @param filename File to disassemble + * @param linenum Line number within the file + * @param lines Number of lines of disassembled code to produce + * @param drm Disassembled code + */ + public void getInstructions( + IDisassemblyDMContext context, + String filename, + int linenum, + int lines, + DataRequestMonitor drm); + + /** + * Gets the mixed disassembled code from an address range. + * If [startAddress] == null, disassemble from the instruction pointer. + * + * @param context Context of the disassembly code + * @param startAddress Beginning address + * @param endAddress End address + * @param drm Disassembled code + */ + public void getMixedInstructions( + IDisassemblyDMContext context, + BigInteger startAddress, + BigInteger endAddress, + DataRequestMonitor drm); + + /** + * Gets the mixed disassembled code from a file location. + * If [lines] == -1, the whole function is disassembled. + * + * @param context Context of the disassembly code + * @param filename File to disassemble + * @param linenum Line number within the file + * @param lines Number of lines of disassembled code to produce + * @param drm Disassembled code + */ + public void getMixedInstructions( + IDisassemblyDMContext context, + String filename, + int linenum, + int lines, + DataRequestMonitor drm); + +} diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IInstruction.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IInstruction.java new file mode 100644 index 00000000000..c51e8ae0542 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IInstruction.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.dsf.debug.service; + +import java.math.BigInteger; + +/** + * Represents an assembly instruction + */ +public interface IInstruction { + + /** + * @return the instruction address. + */ + BigInteger getAdress(); + + /** + * @return the function name. + */ + String getFuntionName(); + + /** + * @return the offset of this machine instruction + */ + long getOffset(); + + /** + * @return the instruction. + */ + String getInstruction(); + + /** + * @return the opcode + */ + String getOpcode(); + + /** + * @return any arguments to the instruction + */ + String getArgs(); + +} diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMixedInstruction.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMixedInstruction.java new file mode 100644 index 00000000000..ab93679003b --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMixedInstruction.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.dsf.debug.service; + +/** + * Represents the assembly instruction(s) corresponding to a source line + */ +public interface IMixedInstruction { + + /** + * @return the file name + */ + String getFileName(); + + /** + * @return the line Number. + */ + int getLineNumber(); + + /** + * @return the array of instruction. + */ + IInstruction[] getInstructions(); + +} diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/GdbLaunchDelegate.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/GdbLaunchDelegate.java index ae3f5ff78ee..3824fecf5ec 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/GdbLaunchDelegate.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/GdbLaunchDelegate.java @@ -88,7 +88,7 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate } } - private void launchLocalDebugSession( ILaunchConfiguration config, ILaunch l, IProgressMonitor monitor ) throws CoreException { + private void launchLocalDebugSession( final ILaunchConfiguration config, ILaunch l, IProgressMonitor monitor ) throws CoreException { if ( monitor.isCanceled() ) { return; } @@ -154,8 +154,9 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate GDBControl gdbControl = tracker.getService(GDBControl.class); if (gdbControl != null) { IMemoryBlockRetrieval memRetrieval = new DsfMemoryBlockRetrieval( - GDB_DEBUG_MODEL_ID, (IMemoryDMContext)gdbControl.getControlDMContext()); + GDB_DEBUG_MODEL_ID, config, (IMemoryDMContext)gdbControl.getControlDMContext()); launch.getSession().registerModelAdapter(IMemoryBlockRetrieval.class, memRetrieval); + ((DsfMemoryBlockRetrieval) memRetrieval).initialize(); } tracker.dispose(); return null; diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/LaunchSequence.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/LaunchSequence.java index 040e7d3a975..240bc0ba787 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/LaunchSequence.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/LaunchSequence.java @@ -33,6 +33,7 @@ import org.eclipse.dd.mi.service.CSourceLookup; import org.eclipse.dd.mi.service.ExpressionService; import org.eclipse.dd.mi.service.MIBreakpoints; import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIDisassembly; import org.eclipse.dd.mi.service.MIMemory; import org.eclipse.dd.mi.service.MIModules; import org.eclipse.dd.mi.service.MIRegisters; @@ -121,6 +122,10 @@ public class LaunchSequence extends Sequence { public void execute(RequestMonitor requestMonitor) { new MIRegisters(fSession).initialize(requestMonitor); }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIDisassembly(fSession).initialize(requestMonitor); + }}, /* * If needed, insert breakpoint at main and run to it. */ diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/ShutdownSequence.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/ShutdownSequence.java index b902a74bd80..e0dbd93c59a 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/ShutdownSequence.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/launching/ShutdownSequence.java @@ -24,6 +24,7 @@ import org.eclipse.dd.mi.service.CSourceLookup; import org.eclipse.dd.mi.service.ExpressionService; import org.eclipse.dd.mi.service.MIBreakpoints; import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIDisassembly; import org.eclipse.dd.mi.service.MIMemory; import org.eclipse.dd.mi.service.MIModules; import org.eclipse.dd.mi.service.MIRegisters; @@ -63,6 +64,11 @@ public class ShutdownSequence extends Sequence { fTracker = null; requestMonitor.done(); } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIDisassembly.class, requestMonitor); + } }, new Step() { @Override public void execute(RequestMonitor requestMonitor) { diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/service/command/GDBControlDMContext.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/service/command/GDBControlDMContext.java index 808536dfd15..ea3741e6e81 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/service/command/GDBControlDMContext.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/service/command/GDBControlDMContext.java @@ -11,6 +11,7 @@ package org.eclipse.dd.gdb.service.command; import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.dsf.debug.service.IDisassembly.IDisassemblyDMContext; import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext; import org.eclipse.dd.dsf.debug.service.IModules.ISymbolDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; @@ -23,7 +24,7 @@ import org.eclipse.dd.mi.service.command.MIControlDMContext; */ public class GDBControlDMContext extends MIControlDMContext implements IContainerDMContext, ISymbolDMContext, IMemoryDMContext, IBreakpointsTargetDMContext, ISourceLookupDMContext, - ISignalsDMContext + ISignalsDMContext, IDisassemblyDMContext { public GDBControlDMContext(String sessionId, String commandControlId) { diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIDisassembly.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIDisassembly.java new file mode 100644 index 00000000000..b8cad253a70 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIDisassembly.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service; + +import java.math.BigInteger; +import java.util.Hashtable; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.debug.service.IDisassembly; +import org.eclipse.dd.dsf.debug.service.IInstruction; +import org.eclipse.dd.dsf.debug.service.IMixedInstruction; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.MIDataDisassemble; +import org.eclipse.dd.mi.service.command.output.MIDataDisassembleInfo; +import org.osgi.framework.BundleContext; + +public class MIDisassembly extends AbstractDsfService implements IDisassembly { + + // Services + ICommandControl fConnection; + + /////////////////////////////////////////////////////////////////////////// + // AbstractDsfService + /////////////////////////////////////////////////////////////////////////// + + /** + * The service constructor + * + * @param session The debugging session + */ + public MIDisassembly(DsfSession session) { + super(session); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#initialize(org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + @Override + public void initialize(final RequestMonitor rm) { + super.initialize(new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + doInitialize(rm); + } + }); + } + + private void doInitialize(final RequestMonitor rm) { + fConnection = getServicesTracker().getService(ICommandControl.class); +// getSession().addServiceEventListener(this, null); + register(new String[] { IDisassembly.class.getName(), MIDisassembly.class.getName() }, + new Hashtable()); + rm.done(); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#shutdown(org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + @Override + public void shutdown(RequestMonitor rm) { + unregister(); +// getSession().removeServiceEventListener(this); + rm.done(); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#getBundleContext() + */ + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + /////////////////////////////////////////////////////////////////////////// + // IDisassembly + /////////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IDisassembly#getInstructions(org.eclipse.dd.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.math.BigInteger, java.math.BigInteger, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getInstructions(IDisassemblyDMContext context, + BigInteger startAddress, BigInteger endAddress, + final DataRequestMonitor drm) + { + // Validate the context + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + drm.done(); + return; + } + + // Go for it + String start = (startAddress != null) ? startAddress.toString() : "$pc"; //$NON-NLS-1$ + String end = (endAddress != null) ? endAddress.toString() : "$pc + 100"; //$NON-NLS-1$ + fConnection.queueCommand(new MIDataDisassemble(context, start, end, false), + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + IInstruction[] result = getData().getMIAssemblyCode(); + drm.setData(result); + drm.done(); + } + }); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IDisassembly#getInstructions(org.eclipse.dd.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.lang.String, int, int, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getInstructions(IDisassemblyDMContext context, String filename, + int linenum, int lines, final DataRequestMonitor drm) + { + // Validate the context + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + drm.done(); + return; + } + + // Go for it + fConnection.queueCommand(new MIDataDisassemble(context, filename, linenum, lines, false), + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + IInstruction[] result = getData().getMIAssemblyCode(); + drm.setData(result); + drm.done(); + } + }); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IDisassembly#getMixedInstructions(org.eclipse.dd.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.math.BigInteger, java.math.BigInteger, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getMixedInstructions(IDisassemblyDMContext context, + BigInteger startAddress, BigInteger endAddress, + final DataRequestMonitor drm) + { + // Validate the context + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + drm.done(); + return; + } + + // Go for it + String start = (startAddress != null) ? startAddress.toString() : "$pc"; //$NON-NLS-1$ + String end = (endAddress != null) ? endAddress.toString() : "$pc + 100"; //$NON-NLS-1$ + fConnection.queueCommand(new MIDataDisassemble(context, start, end, true), + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + IMixedInstruction[] result = getData().getMIMixedCode(); + drm.setData(result); + drm.done(); + } + }); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IDisassembly#getMixedInstructions(org.eclipse.dd.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.lang.String, int, int, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getMixedInstructions(IDisassemblyDMContext context, + String filename, int linenum, int lines, + final DataRequestMonitor drm) + { + // Validate the context + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + drm.done(); + return; + } + + // Go for it + fConnection.queueCommand(new MIDataDisassemble(context, filename, linenum, lines, true), + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + IMixedInstruction[] result = getData().getMIMixedCode(); + drm.setData(result); + drm.done(); + } + }); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataDisassemble.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataDisassemble.java new file mode 100644 index 00000000000..df8fb0d88fb --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataDisassemble.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IDisassembly.IDisassemblyDMContext; +import org.eclipse.dd.mi.service.command.output.MIDataDisassembleInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * -data-disassemble + * [ -s START-ADDR -e END-ADDR ] + * | [ -f FILENAME -l LINENUM [ -n LINES ] ] + * -- MODE + * + * Where: + * + * '-s START-ADDR' + * is the beginning address (or '$pc') + * + * '-e END-ADDR' + * is the end address + * + * '-f FILENAME' + * is the name of the file to disassemble + * + * '-l LINENUM' + * is the line number to disassemble around + * + * -n LINES' + * is the the number of disassembly lines to be produced. If it is + * -1, the whole function will be disassembled, in case no END-ADDR is + * specified. If END-ADDR is specified as a non-zero value, and + * LINES is lower than the number of disassembly lines between + * START-ADDR and END-ADDR, only LINES lines are displayed; if LINES + * is higher than the number of lines between START-ADDR and + * END-ADDR, only the lines up to END-ADDR are displayed. + * + * '-- MODE' + * is either 0 (meaning only disassembly) or 1 (meaning mixed source + * and disassembly). + */ + +public class MIDataDisassemble extends MICommand { + + public MIDataDisassemble(IDisassemblyDMContext ctx, String start, String end, boolean mode) { + super(ctx, "-data-disassemble"); //$NON-NLS-1$ + setOptions(new String[]{"-s", start, "-e", end}); //$NON-NLS-1$ //$NON-NLS-2$ + String mixed = "0"; //$NON-NLS-1$ + if (mode) { + mixed = "1"; //$NON-NLS-1$ + } + setParameters(new String[]{mixed}); + } + + public MIDataDisassemble(IDisassemblyDMContext ctx, String file, int linenum, int lines, boolean mode) { + super(ctx, "-data-disassemble"); //$NON-NLS-1$ + setOptions(new String[]{"-f", file, "-l", //$NON-NLS-1$ //$NON-NLS-2$ + Integer.toString(linenum), "-n", Integer.toString(lines)}); //$NON-NLS-1$ + String mixed = "0"; //$NON-NLS-1$ + if (mode) { + mixed = "1"; //$NON-NLS-1$ + } + setParameters(new String[]{mixed}); + } + + /* + * GDB the -data-disassemble uses "--" as a separator wit only the MODE + * So override the MICommand + */ + @Override + protected String parametersToString() { + String[] parameters = getParameters(); + if (parameters != null && parameters.length > 0) { + return "-- " + parameters[0]; //$NON-NLS-1$ + } + return new String(); + } + + @Override + public MIDataDisassembleInfo getResult(MIOutput output) { + return new MIDataDisassembleInfo(output); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataDisassembleInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataDisassembleInfo.java new file mode 100644 index 00000000000..14f28cb2b79 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataDisassembleInfo.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * The parsed output of the data-disassemble command. The output format is + * determined by the mode field on the request. + * + * -data-disassemble -s $pc -e "$pc + 20" -- 0 + * ^done,asm_insns=[ + * {address="0x000107c0",func-name="main",offset="4",inst="mov 2, %o0"}, + * {address="0x000107c4",func-name="main",offset="8",inst="sethi %hi(0x11800), %o2"}, + * {address="0x000107c8",func-name="main",offset="12",inst="or %o2, 0x140, %o1\t! 0x11940 <_lib_version+8>"}, + * {address="0x000107cc",func-name="main",offset="16",inst="sethi %hi(0x11800), %o2"}, + * {address="0x000107d0",func-name="main",offset="20",inst="or %o2, 0x168, %o4\t! 0x11968 <_lib_version+48>"}] + * + * -data-disassemble -f basics.c -l 32 -- 0 + * ^done,asm_insns=[ + * {address="0x000107bc",func-name="main",offset="0",inst="save %sp, -112, %sp"}, + * {address="0x000107c0",func-name="main",offset="4",inst="mov 2, %o0"}, + * {address="0x000107c4",func-name="main",offset="8",inst="sethi %hi(0x11800), %o2"}, + * [...] + * {address="0x0001081c",func-name="main",offset="96",inst="ret "}, + * {address="0x00010820",func-name="main",offset="100",inst="restore "}] + * + * -data-disassemble -f basics.c -l 32 -n 3 -- 1 + * ^done,asm_insns=[ + * src_and_asm_line={line="31",file="/dir1/dir2/basics.c",line_asm_insn=[ + * {address="0x000107bc",func-name="main",offset="0",inst="save %sp, -112, %sp"}]}, + * src_and_asm_line={line="32",file="/dir1/dir2/basics.c",line_asm_insn=[ + * {address="0x000107c0",func-name="main",offset="4",inst="mov 2, %o0"}, + * {address="0x000107c4",func-name="main",offset="8",inst="sethi %hi(0x11800), %o2"}]}] + * + */ + +public class MIDataDisassembleInfo extends MIInfo { + + // The parsed information + private boolean mixed; + private MIMixedInstruction[] mixedCode; + private MIInstruction[] assemblyCode; + + public MIDataDisassembleInfo(MIOutput record) { + super(record); + mixed = false; + parse(); + } + + public boolean isMixed() { + return mixed; + } + + public MIInstruction[] getMIAssemblyCode() { + return assemblyCode; + } + + public MIMixedInstruction[] getMIMixedCode() { + return mixedCode; + } + + /** + * Find the relevant tag in the output record ("asm_insns") and then + * parse its value. + */ + private void parse() { + List asmList = new ArrayList(); + List srcList = new ArrayList(); + + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + // Technically, there should be only one field (asm_insns), but just in case... + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("asm_insns")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIList) { + parseResult((MIList) value, srcList, asmList); + } + } + } + } + } + + assemblyCode = asmList.toArray(new MIInstruction[asmList.size()]); + mixedCode = srcList.toArray(new MIMixedInstruction[srcList.size()]); + } + + /** + * Parse the back-end result. Depending on the requested mode + * ("-- 0" or "-- 1" on the request), the result has one of the + * following forms: + * + * [1] Mode == 0 (assembly instructions only) + * {address="0x000107c0",func-name="main",offset="4",inst="mov 2, %o0"}, + * {address="0x000107c4",func-name="main",offset="8",inst="sethi %hi(0x11800), %o2"}, + * ..., + * {address="0x00010820",func-name="main",offset="100",inst="restore "} + * + * [2] Mode == 1 (Mixed source and assembly code) + * src_and_asm_line={ + * line="31",file="/dir1/dir2/basics.c", + * line_asm_insn=[ + * {address="0x000107c0",func-name="main",offset="4",inst="mov 2, %o0"}, + * {address="0x000107c4",func-name="main",offset="8",inst="sethi %hi(0x11800), %o2"}, + * ..., + * {address="0x00010820",func-name="main",offset="100",inst="restore "} + * ] + * }, + * ..., + * src_and_asm_line={ + * line="31",file="/dir1/dir2/basics.c", + * line_asm_insn=[ + * ..., + * ] + * } + */ + private void parseResult(MIList list, + List srcList, List asmList) { + + // Mixed mode (with source) + MIResult[] results = list.getMIResults(); + if (results != null && results.length > 0) { + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("src_and_asm_line")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + srcList.add(new MIMixedInstruction((MITuple) value)); + } + } + } + mixed = true; + } + + // Non-mixed mode + MIValue[] values = list.getMIValues(); + if (values != null && values.length > 0) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof MITuple) { + asmList.add(new MIInstruction((MITuple) values[i])); + } + } + mixed = false; + } + + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInstruction.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInstruction.java new file mode 100644 index 00000000000..50863384d7d --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInstruction.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Adapted for DSF + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.math.BigInteger; + +import org.eclipse.dd.dsf.debug.service.IInstruction; + +public class MIInstruction implements IInstruction { + + // The parsed information + BigInteger address; + String function = ""; //$NON-NLS-1$ + long offset; + String opcode = ""; //$NON-NLS-1$ + String args = ""; //$NON-NLS-1$ + + public MIInstruction(MITuple tuple) { + parse(tuple); + } + + public BigInteger getAdress() { + return address; + } + + public String getFuntionName() { + return function; + } + + public long getOffset() { + return offset; + } + + public String getInstruction() { + return opcode + " " + args; //$NON-NLS-1$; + } + + public String getOpcode() { + return opcode; + } + + public String getArgs() { + return args; + } + + /** + * Parse the assembly instruction result. Each instruction has the following + * fields: + * - Address + * - Function name + * - Offset + * - Instruction + * + * {address="0x000107c0",func-name="main",offset="4",inst="mov 2, %o0"}, + * {address="0x000107c4",func-name="main",offset="8",inst="sethi %hi(0x11800), %o2"}, + * ..., + * {address="0x00010820",func-name="main",offset="100",inst="restore "} + * + * In addition, the opcode and arguments are extracted form the assembly instruction. + */ + private void parse(MITuple tuple) { + MIResult[] results = tuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + + if (value != null && value instanceof MIConst) { + str = ((MIConst)value).getCString(); + } + + if (var.equals("address")) { //$NON-NLS-1$ + try { + address = new BigInteger(str.trim(), 16); + } catch (NumberFormatException e) { + } + continue; + } + + if (var.equals("func-name")) { //$NON-NLS-1$ + function = str; + continue; + } + + if (var.equals("offset")) { //$NON-NLS-1$ + try { + offset = Long.decode(str.trim()).longValue(); + } catch (NumberFormatException e) { + } + continue; + } + + if (var.equals("inst")) { //$NON-NLS-1$ + /* for the instruction, we do not want the C string but the + translated string since the only thing we are doing is + displaying it. */ + str = ((MIConst) value).getString(); + + char chars[] = str.toCharArray(); + int index = 0; + + // count the non-whitespace characters. + while( (index < chars.length) && (chars[index] > '\u0020')) + index++; + + opcode = str.substring( 0, index ); + + // skip any whitespace characters + while( index < chars.length && chars[index] >= '\u0000' && chars[index] <= '\u0020') + index++; + + // guard no argument + if( index < chars.length ) + args = str.substring( index ); + } + } + + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIMixedInstruction.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIMixedInstruction.java new file mode 100644 index 00000000000..a430a0155cd --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIMixedInstruction.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Adapted for DSF + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.dd.dsf.debug.service.IInstruction; +import org.eclipse.dd.dsf.debug.service.IMixedInstruction; + +public class MIMixedInstruction implements IMixedInstruction { + + // The parsed information + private String fileName = ""; //$NON-NLS-1$ + private int lineNumber = 0; + private MIInstruction[] assemblyCode; + + public MIMixedInstruction(MITuple tuple) { + parse(tuple); + } + + public String getFileName() { + return fileName; + } + + public int getLineNumber() { + return lineNumber; + } + + public IInstruction[] getInstructions() { + return assemblyCode; + } + + /** + * Parse the mixed instruction result. It has the following 3 fields: + * + * line="31", + * file="/dir1/dir2/basics.c", + * line_asm_insn=[ + * {address="0x000107c0",func-name="main",offset="4",inst="mov 2, %o0"}, + * {address="0x000107c4",func-name="main",offset="8",inst="sethi %hi(0x11800), %o2"}, + * ..., + * {address="0x00010820",func-name="main",offset="100",inst="restore "} + * ] + */ + private void parse(MITuple tuple) { + List instructions = new ArrayList(); + MIResult[] results = tuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + + if (value != null && value instanceof MIConst) { + str = ((MIConst) value).getCString(); + } + + if (var.equals("line")) { //$NON-NLS-1$ + try { + lineNumber = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + continue; + } + + if (var.equals("file")) { //$NON-NLS-1$ + fileName = str; + continue; + } + + if (var.equals("line_asm_insn")) { //$NON-NLS-1$ + if (value instanceof MIList) { + MIList list = (MIList) value; + MIValue[] values = list.getMIValues(); + for (int j = 0; j < values.length; j++) { + if (values[j] instanceof MITuple) { + instructions.add(new MIInstruction((MITuple) values[j])); + } + } + } + } + } + assemblyCode = instructions.toArray(new MIInstruction[instructions.size()]); + + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe new file mode 100755 index 00000000000..001fd61c5ce Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe new file mode 100755 index 00000000000..021d8981d19 Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe new file mode 100755 index 00000000000..7eb311144cc Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe new file mode 100755 index 00000000000..be5c37d13e4 Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe new file mode 100755 index 00000000000..c0f4b38faef Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe new file mode 100755 index 00000000000..97775965e40 Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIDisassemblyTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIDisassemblyTest.java new file mode 100644 index 00000000000..f9ecaccff59 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIDisassemblyTest.java @@ -0,0 +1,592 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - Initial Implementation + *******************************************************************************/ + +package org.eclipse.dd.tests.gdb; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +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.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.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.gdb.service.command.GDBControlDMContext; +import org.eclipse.dd.mi.service.MIDisassembly; +import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.dd.tests.gdb.framework.BackgroundRunner; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.eclipse.dd.tests.gdb.framework.SyncUtil; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +/* + * This is the Disassembly Service test suite. + * + * It is meant to be a regression suite to be executed automatically against + * the DSF nightly builds. + * + * It is also meant to be augmented with a proper test case(s) every time a + * feature is added or in the event (unlikely :-) that a bug is found in the + * Disassembly Service. + * + * Refer to the JUnit4 documentation for an explanation of the annotations. + */ + +@RunWith(BackgroundRunner.class) +public class MIDisassemblyTest extends BaseTestCase { + + private static final String FILE_NAME = "MemoryTestApp.cc"; + private static final int LINE_NUMBER = 35; + private static final String INVALID_FILE_NAME = "invalid_filename"; + + private final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + private DsfSession fSession; + private DsfServicesTracker fServicesTracker; + private GDBControlDMContext fGdbControlDmc; + private MIDisassembly fDisassembly; + private IExpressions fExpressionService; + + // ======================================================================== + // Housekeeping stuff + // ======================================================================== + + @BeforeClass + public static void testSuiteInitialization() { + // Select the binary to run the tests against + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, "data/launch/bin/MemoryTestApp.exe"); + } + + @AfterClass + public static void testSuiteCleanup() { + } + + @Before + public void testCaseInitialization() { + fSession = getGDBLaunch().getSession(); + + // Get a reference to the memory service + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); + assert(fServicesTracker != null); + + GDBControl gdbControl = fServicesTracker.getService(GDBControl.class); + fGdbControlDmc = gdbControl.getGDBDMContext(); + assert(fGdbControlDmc != null); + + fDisassembly = fServicesTracker.getService(MIDisassembly.class); + assert(fDisassembly != null); + + fExpressionService = fServicesTracker.getService(IExpressions.class); + assert(fExpressionService != null); + +// fSession.addServiceEventListener(MIDisassemblyTest.this, null); + } + + @After + public void testCaseCleanup() { + // Clear the references (not strictly necessary) +// fSession.removeServiceEventListener(MIDisassemblyTest.this); + fExpressionService = null; + fDisassembly = null; + fServicesTracker.dispose(); + fServicesTracker = null; + } + + // ======================================================================== + // Helper Functions + // ======================================================================== + + /* ------------------------------------------------------------------------ + * evaluateExpression + * ------------------------------------------------------------------------ + * Invokes the ExpressionService to evaluate an expression. In theory, we + * shouldn't rely on another service to test this one but we need a way to + * access a variable from the test application in order verify that the + * memory operations (read/write) are working properly. + * ------------------------------------------------------------------------ + * @param expression Expression to resolve + * @return Resolved expression + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private IAddress evaluateExpression(String expression) throws Throwable + { + // Create the expression and format contexts + final IExpressionDMContext expressionDMC = SyncUtil.SyncCreateExpression(fGdbControlDmc, expression); + final FormattedValueDMContext formattedValueDMC = SyncUtil.SyncGetFormattedValue(fExpressionService, expressionDMC, IFormattedValues.HEX_FORMAT); + + // Create the DataRequestMonitor which will store the operation result in the wait object + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Evaluate the expression (asynchronously) + fSession.getExecutor().submit(new Runnable() { + public void run() { + fExpressionService.getFormattedExpressionValue(formattedValueDMC, drm); + } + }); + + // Wait for completion + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Return the string formatted by the back-end + String result = ""; + Object returnInfo = fWait.getReturnInfo(); + if (returnInfo instanceof FormattedValueDMData) + result = ((FormattedValueDMData) returnInfo).getFormattedValue(); + return new Addr64(result); + } + + /* ------------------------------------------------------------------------ + * getInstruction + * ------------------------------------------------------------------------ + * Issues a disassembly request. The result is stored in fWait. + * ------------------------------------------------------------------------ + * Typical usage: + * getInstruction(dmc, start, end); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param start the start address (null == $pc) + * @param end the end address + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void getInstruction(final IDisassemblyDMContext dmc, + final BigInteger startAddress, final BigInteger endAddress) + throws InterruptedException + { + // Set the Data Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Issue the get memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fDisassembly.getInstructions(dmc, startAddress, endAddress, drm); + } + }); + } + + /* ------------------------------------------------------------------------ + * getInstruction + * ------------------------------------------------------------------------ + * Issues a disassembly request. The result is stored in fWait. + * ------------------------------------------------------------------------ + * Typical usage: + * getInstruction(dmc, start, end); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param fucntion the function + * @param linenum the line + * @param count the instruction count + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void getInstruction(final IDisassemblyDMContext dmc, + final String function, final int linenum, final int count) + throws InterruptedException + { + // Set the Data Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Issue the get memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fDisassembly.getInstructions(dmc, function, linenum, count, drm); + } + }); + } + + /* ------------------------------------------------------------------------ + * getMixedInstruction + * ------------------------------------------------------------------------ + * Issues a disassembly request. The result is stored in fWait. + * ------------------------------------------------------------------------ + * Typical usage: + * getInstruction(dmc, start, end); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param start the start address (null == $pc) + * @param end the end address + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void getMixedInstruction(final IDisassemblyDMContext dmc, + final BigInteger startAddress, final BigInteger endAddress) + throws InterruptedException + { + // Set the Data Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Issue the get memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fDisassembly.getMixedInstructions(dmc, startAddress, endAddress, drm); + } + }); + } + + + /* ------------------------------------------------------------------------ + * getMixedInstruction + * ------------------------------------------------------------------------ + * Issues a disassembly request. The result is stored in fWait. + * ------------------------------------------------------------------------ + * Typical usage: + * getInstruction(dmc, start, end); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param start the start address (null == $pc) + * @param end the end address + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void getMixedInstruction(final IDisassemblyDMContext dmc, + final String function, final int linenum, final int count) + throws InterruptedException + { + // Set the Data Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Issue the get memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fDisassembly.getMixedInstructions(dmc, function, linenum, count, drm); + } + }); + } + + // ======================================================================== + // Test Cases + // ------------------------------------------------------------------------ + // Templates: + // ------------------------------------------------------------------------ + // @ Test + // public void basicTest() { + // // First test to run + // assertTrue("", true); + // } + // ------------------------------------------------------------------------ + // @ Test(timeout=5000) + // public void timeoutTest() { + // // Second test to run, which will timeout if not finished on time + // assertTrue("", true); + // } + // ------------------------------------------------------------------------ + // @ Test(expected=FileNotFoundException.class) + // public void exceptionTest() throws FileNotFoundException { + // // Third test to run which expects an exception + // throw new FileNotFoundException("Just testing"); + // } + // ======================================================================== + + /////////////////////////////////////////////////////////////////////////// + // getMemory tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // readWithNullContext + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithNullContext() throws Throwable { + + // Setup call parameters + BigInteger startAddress = null; + BigInteger endAddress = null; + + // Perform the test + fWait.waitReset(); + getInstruction(null, startAddress, endAddress); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + String expected = "Unknown context type"; + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + } + + // ------------------------------------------------------------------------ + // readWithInvalidAddress + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithInvalidAddress() throws Throwable { + + // Setup call parameters + BigInteger startAddress = BigInteger.ZERO; + BigInteger endAddress = null; + + // Perform the test + fWait.waitReset(); + getInstruction(fGdbControlDmc, startAddress, endAddress); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + String expected = "Cannot access memory at address"; + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + } + + // ------------------------------------------------------------------------ + // readWithNullAddress + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithNullAddress() throws Throwable { + + // Setup call parameters + BigInteger startAddress = null; + BigInteger endAddress = null; + + // Perform the test + fWait.waitReset(); + getInstruction(fGdbControlDmc, startAddress, endAddress); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + assertTrue(fWait.getMessage(), fWait.isOK()); + IInstruction[] result = (IInstruction[]) fWait.getReturnInfo(); + assertTrue("No instruction retrieved", result.length != 0); + } + + // ------------------------------------------------------------------------ + // readWithValidAddress + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithValidAddress() throws Throwable { + + // Setup call parameters + Addr64 main = (Addr64) evaluateExpression("&main"); + BigInteger startAddress = main.getValue(); + BigInteger endAddress = null; + + // Perform the test + fWait.waitReset(); + getInstruction(fGdbControlDmc, startAddress, endAddress); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + assertTrue(fWait.getMessage(), fWait.isOK()); + IInstruction[] result = (IInstruction[]) fWait.getReturnInfo(); + assertTrue("No instruction retrieved", result.length != 0); + } + + // ------------------------------------------------------------------------ + // readWithInvalidFilename + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithValidFunction() throws Throwable { + + // Setup call parameters + String filename = INVALID_FILE_NAME; + int linenum = 1; + int count = -1; + + // Perform the test + fWait.waitReset(); + getInstruction(fGdbControlDmc, filename, linenum, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + String expected = "Invalid filename"; + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + } + + // ------------------------------------------------------------------------ + // readWithInvalidLineNumber + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithInvalidLineNumber() throws Throwable { + + // Setup call parameters + String filename = FILE_NAME; + int linenum = -1; + int count = -1; + + // Perform the test + fWait.waitReset(); + getInstruction(fGdbControlDmc, filename, linenum, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + String expected = "Invalid line number"; + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + } + + // ------------------------------------------------------------------------ + // readWithValidFilename + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithValidFilename() throws Throwable { + + // Setup call parameters + String filename = FILE_NAME; + int linenum = LINE_NUMBER; + int count = -1; + + // Perform the test + fWait.waitReset(); + getInstruction(fGdbControlDmc, filename, linenum, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + assertTrue(fWait.getMessage(), fWait.isOK()); + IInstruction[] result = (IInstruction[]) fWait.getReturnInfo(); + assertTrue("No instruction retrieved", result.length != 0); + } + + // ------------------------------------------------------------------------ + // readWithLineCount + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readWithLineCount() throws Throwable { + + // Setup call parameters + String filename = FILE_NAME; + int linenum = LINE_NUMBER; + int count = 5; + + // Perform the test + fWait.waitReset(); + getInstruction(fGdbControlDmc, filename, linenum, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + assertTrue(fWait.getMessage(), fWait.isOK()); + IInstruction[] result = (IInstruction[]) fWait.getReturnInfo(); + assertTrue("Wrong number of instructions retrieved, expected " + count + ", got " + result.length, + result.length == count); + } + + // ------------------------------------------------------------------------ + // readMixedWithValidAddress + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readMixedWithValidAddress() throws Throwable { + + // Setup call parameters + Addr64 main = (Addr64) evaluateExpression("&main"); + BigInteger startAddress = main.getValue(); + BigInteger endAddress = null; + + // Perform the test + fWait.waitReset(); + getMixedInstruction(fGdbControlDmc, startAddress, endAddress); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + assertTrue(fWait.getMessage(), fWait.isOK()); + IMixedInstruction[] result = (IMixedInstruction[]) fWait.getReturnInfo(); + assertTrue("No instruction retrieved", result.length != 0); + } + + // ------------------------------------------------------------------------ + // readMixedWithLineCount + // ------------------------------------------------------------------------ + @Test(timeout=20000) + public void readMixedWithLineCount() throws Throwable { + + // Setup call parameters + String filename = FILE_NAME; + int linenum = LINE_NUMBER; + int count = 5; + + // Perform the test + fWait.waitReset(); + getMixedInstruction(fGdbControlDmc, filename, linenum, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + // Verify the result + assertTrue(fWait.getMessage(), fWait.isOK()); + IMixedInstruction[] result = (IMixedInstruction[]) fWait.getReturnInfo(); + int total = 0; + for (IMixedInstruction mixed : result) { + IInstruction[] inst = mixed.getInstructions(); + total += inst.length; + } + assertTrue("Wrong number of instructions retrieved, expected " + count + ", got " + result.length, + total == count); + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java index 1519319ee3a..52cd80c287c 100644 --- a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java @@ -34,6 +34,7 @@ import org.eclipse.dd.mi.service.CSourceLookup; import org.eclipse.dd.mi.service.ExpressionService; import org.eclipse.dd.mi.service.MIBreakpoints; import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIDisassembly; import org.eclipse.dd.mi.service.MIMemory; import org.eclipse.dd.mi.service.MIRegisters; import org.eclipse.dd.mi.service.MIStack; @@ -226,6 +227,10 @@ public class LaunchSequence extends Sequence { public void execute(RequestMonitor requestMonitor) { new MIRegisters(fSession).initialize(requestMonitor); }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIDisassembly(fSession).initialize(requestMonitor); + }}, /*new Step() { public void execute(RequestMonitor requestMonitor) { new GDBVariables(fSession).initialize(requestMonitor); }},*/ diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java index 787826a4a29..1a4ce69ad4f 100644 --- a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java @@ -23,6 +23,7 @@ import org.eclipse.dd.mi.service.CSourceLookup; import org.eclipse.dd.mi.service.ExpressionService; import org.eclipse.dd.mi.service.MIBreakpoints; import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIDisassembly; import org.eclipse.dd.mi.service.MIMemory; import org.eclipse.dd.mi.service.MIRegisters; import org.eclipse.dd.mi.service.MIStack; @@ -59,6 +60,7 @@ public class ShutdownSequence extends Sequence { requestMonitor.done(); } }, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(MIDisassembly.class, requestMonitor); }}, new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(MIRegisters.class, requestMonitor); }}, new Step() { // Uninstall the breakpoints before the service is shut down. diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java index 9ff059d98fe..114ee8324c7 100644 --- a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java @@ -89,7 +89,7 @@ public class TestLaunchDelegate extends AbstractCLaunchDelegate } } - private void launchLocalDebugSession( ILaunchConfiguration config, ILaunch l, IProgressMonitor monitor ) throws CoreException { + private void launchLocalDebugSession( final ILaunchConfiguration config, ILaunch l, IProgressMonitor monitor ) throws CoreException { if ( monitor.isCanceled() ) { return; } @@ -151,8 +151,9 @@ public class TestLaunchDelegate extends AbstractCLaunchDelegate GDBControl gdbControl = tracker.getService(GDBControl.class); if (gdbControl != null) { IMemoryBlockRetrieval memRetrieval = new DsfMemoryBlockRetrieval( - GDB_DEBUG_MODEL_ID, gdbControl.getGDBDMContext()); + GDB_DEBUG_MODEL_ID, config, gdbControl.getGDBDMContext()); launch.getSession().registerModelAdapter(IMemoryBlockRetrieval.class, memRetrieval); + ((DsfMemoryBlockRetrieval) memRetrieval).initialize(); } tracker.dispose(); return null; diff --git a/tests/.project b/tests/.project new file mode 100644 index 00000000000..ef6405948af --- /dev/null +++ b/tests/.project @@ -0,0 +1,11 @@ + + + tests + + + + + + + +