From 8868398cc994f54985dfc66faa011dbb010261c1 Mon Sep 17 00:00:00 2001 From: Francois Chouinard Date: Sat, 1 Mar 2008 20:21:08 +0000 Subject: [PATCH] Committing patches for bugs 159946 (disassembly) and 214546 (memory monitor persistence). --- .../dd/dsf/debug/model/DsfMemoryBlock.java | 15 +- .../debug/model/DsfMemoryBlockRetrieval.java | 242 ++++++- .../dd/dsf/debug/service/IDisassembly.java | 91 +++ .../dd/dsf/debug/service/IInstruction.java | 51 ++ .../dsf/debug/service/IMixedInstruction.java | 34 + .../dd/gdb/launching/GdbLaunchDelegate.java | 5 +- .../dd/gdb/launching/LaunchSequence.java | 5 + .../dd/gdb/launching/ShutdownSequence.java | 6 + .../service/command/GDBControlDMContext.java | 3 +- .../eclipse/dd/mi/service/MIDisassembly.java | 200 ++++++ .../command/commands/MIDataDisassemble.java | 93 +++ .../command/output/MIDataDisassembleInfo.java | 164 +++++ .../service/command/output/MIInstruction.java | 130 ++++ .../command/output/MIMixedInstruction.java | 97 +++ .../data/launch/bin/BreakpointTestApp.exe | Bin 0 -> 40081 bytes .../data/launch/bin/ExpressionTestApp.exe | Bin 0 -> 16978 bytes .../data/launch/bin/GDBMIGenericTestApp.exe | Bin 0 -> 9451 bytes .../data/launch/bin/MemoryTestApp.exe | Bin 0 -> 39820 bytes .../data/launch/bin/MultiThread.exe | Bin 0 -> 8979 bytes .../data/launch/bin/SpecialTestApp.exe | Bin 0 -> 9446 bytes .../dd/tests/gdb/MIDisassemblyTest.java | 592 ++++++++++++++++++ .../tests/gdb/launching/LaunchSequence.java | 5 + .../tests/gdb/launching/ShutdownSequence.java | 2 + .../gdb/launching/TestLaunchDelegate.java | 5 +- tests/.project | 11 + 25 files changed, 1708 insertions(+), 43 deletions(-) create mode 100644 plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IDisassembly.java create mode 100644 plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IInstruction.java create mode 100644 plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMixedInstruction.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIDisassembly.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataDisassemble.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataDisassembleInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInstruction.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIMixedInstruction.java create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIDisassemblyTest.java create mode 100644 tests/.project 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 0000000000000000000000000000000000000000..001fd61c5ce05d3399f499d7ffa6b3bd334c24e5 GIT binary patch literal 40081 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 X%mtBO$@o#eRyvX#Kc+rRDdYbO>3z!8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..be5c37d13e43760a7e0d4c1fd281b81aa94b1520 GIT binary patch literal 39820 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..97775965e40792df4c7983d1ea27421660d19bd2 GIT binary patch literal 9446 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 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 + + + + + + + +