1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 09:46:02 +02:00

Bug 322658: Support for new GDB MI command -data-read-memory-bytes. It is already supported in GDB HEAD and will be officialy available with GDB 7.3

This commit is contained in:
Marc Khouzam 2010-08-27 14:01:11 +00:00
parent c31e996fc2
commit fa9a41f13a
9 changed files with 386 additions and 19 deletions

View file

@ -8,13 +8,16 @@
* Contributors:
* Wind River Systems - initial API and implementation
* Ericsson - Modified for additional features in DSF Reference implementation
* Nokia - create and use backend service.
* Nokia - create and use backend service.
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service.command;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import java.util.Map.Entry;
import java.util.concurrent.Future;
@ -597,4 +600,15 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
requestMonitor.done();
}
}
/**
* GDBControl is only used for GDB earlier that 7.0. Although -list-features
* is available in 6.8, it does not report anything we care about, so
* return empty list.
*/
private final List<String> fFeatures = new ArrayList<String>();
/** @since 4.0 */
public List<String> getFeatures() {
return fFeatures;
}
}

View file

@ -9,12 +9,15 @@
* Wind River Systems - initial API and implementation
* Ericsson - Modified for additional features in DSF Reference implementation
* Ericsson - New version for 7_0
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service.command;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.Future;
@ -61,6 +64,7 @@ import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor_7_0;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
@ -116,6 +120,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
private MIInferiorProcess fInferiorProcess = null;
private PTY fPty;
private List<String> fFeatures = new ArrayList<String>();
/**
* @since 3.0
@ -150,6 +155,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
new CommandMonitoringStep(InitializationShutdownStep.Direction.INITIALIZING),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.INITIALIZING),
new CommandProcessorsStep(InitializationShutdownStep.Direction.INITIALIZING),
new ListFeaturesStep(InitializationShutdownStep.Direction.INITIALIZING),
new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING),
};
@ -163,6 +169,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
public void shutdown(final RequestMonitor requestMonitor) {
final Sequence.Step[] shutdownSteps = new Sequence.Step[] {
new RegisterStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new ListFeaturesStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandProcessorsStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandMonitoringStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
@ -238,6 +245,18 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
);
}
private void listFeatures(final RequestMonitor requestMonitor) {
queueCommand(
getCommandFactory().createMIListFeatures(fControlDmc),
new DataRequestMonitor<MIListFeaturesInfo>(getExecutor(), requestMonitor) {
@Override
public void handleSuccess() {
fFeatures = getData().getFeatures();
super.handleSuccess();
}
});
}
/*
* This method does the necessary work to setup the input/output streams for the
* inferior process, by either preparing the PTY to be used, to simply leaving
@ -572,6 +591,11 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
countingRm.setDoneCount(count);
}
/**@since 4.0 */
public List<String> getFeatures() {
return fFeatures;
}
@DsfServiceEventHandler
public void eventDispatched(ICommandControlShutdownDMEvent e) {
// Handle our "GDB Exited" event and stop processing commands.
@ -723,6 +747,21 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
}
}
/** @since 4.0 */
protected class ListFeaturesStep extends InitializationShutdownStep {
ListFeaturesStep(Direction direction) { super(direction); }
@Override
protected void initialize(final RequestMonitor requestMonitor) {
listFeatures(requestMonitor);
}
@Override
protected void shutdown(RequestMonitor requestMonitor) {
requestMonitor.done();
}
}
protected class RegisterStep extends InitializationShutdownStep {
RegisterStep(Direction direction) { super(direction); }
@Override

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2010 Ericsson and others.
* Copyright (c) 2008, 2010 Ericsson and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse License v1.0
* which accompanies this distribution, and is available at
@ -7,10 +7,12 @@
*
* Contributors:
* Ericsson - initial API and implementation
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service.command;
import java.io.OutputStream;
import java.util.List;
import java.util.Properties;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
@ -53,4 +55,15 @@ public interface IGDBControl extends IMICommandControl {
* @since 3.0
*/
void setEnvironment(Properties props, boolean clear, RequestMonitor requestMonitor);
/**
* Returns a list of all the target-independent MI features
* supported by the GDB that is being used. Consult the GDB MI documentation
* for the MI -list-features command for the possible names of features.
*
* The return value is never null but may be an empty list.
*
* @since 4.0
*/
List<String> getFeatures();
}

View file

@ -10,6 +10,7 @@
* Ericsson AB - expanded from initial stub
* Ericsson AB - added support for event handling
* Ericsson AB - added memory cache
* Vladimir Prus (CodeSourcery) - support for -data-read-memory-bytes (bug 322658)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
@ -29,9 +30,9 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IMemory;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IMemory;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
@ -39,10 +40,11 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.MIExpressions.ExpressionChangedEvent;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataReadMemoryBytesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataReadMemoryInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataWriteMemoryInfo;
import org.eclipse.cdt.dsf.service.AbstractDsfService;
@ -59,6 +61,8 @@ import org.osgi.framework.BundleContext;
*/
public class MIMemory extends AbstractDsfService implements IMemory, ICachingService {
private static final String READ_MEMORY_BYTES_FEATURE = "data-read-memory-bytes"; //$NON-NLS-1$
public class MemoryChangedEvent extends AbstractDMEvent<IMemoryDMContext>
implements IMemoryChangedEvent
{
@ -91,6 +95,10 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
return cache;
}
// Whether the -data-read-memory-bytes should be used
// instead of -data-read-memory
private boolean fDataReadMemoryBytes;
/**
* Constructor
*/
@ -128,9 +136,11 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
*/
private void doInitialize(final RequestMonitor requestMonitor) {
// Create the command cache
ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class);
IGDBControl commandControl = getServicesTracker().getService(IGDBControl.class);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(commandControl, getExecutor(), 2);
fDataReadMemoryBytes = commandControl.getFeatures().contains(READ_MEMORY_BYTES_FEATURE);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
// This cache stores the result of a command when received; also, this cache
@ -319,15 +329,32 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
protected void readMemoryBlock(IDMContext dmc, IAddress address, final long offset,
final int word_size, final int count, final DataRequestMonitor<MemoryByte[]> drm)
{
/* To simplify the parsing of the MI result, we request the output to
* be on 1 row of [count] columns, no char interpretation.
*/
int mode = MIFormat.HEXADECIMAL;
int nb_rows = 1;
int nb_cols = count;
Character asChar = null;
if (fDataReadMemoryBytes) {
fCommandCache.execute(
fCommandFactory.createMIDataReadMemoryBytes(dmc, address.toString(), offset*word_size, count*word_size),
new DataRequestMonitor<MIDataReadMemoryBytesInfo>(getExecutor(), drm) {
@Override
protected void handleSuccess() {
// Retrieve the memory block
drm.setData(getData().getMIMemoryBlock());
drm.done();
}
@Override
protected void handleFailure() {
drm.setData(createInvalidBlock(word_size * count));
drm.done();
}
});
} else {
/* To simplify the parsing of the MI result, we request the output to
* be on 1 row of [count] columns, no char interpretation.
*/
int mode = MIFormat.HEXADECIMAL;
int nb_rows = 1;
int nb_cols = count;
Character asChar = null;
fCommandCache.execute(
fCommandCache.execute(
fCommandFactory.createMIDataReadMemory(dmc, offset, address.toString(), mode, word_size, nb_rows, nb_cols, asChar),
new DataRequestMonitor<MIDataReadMemoryInfo>(getExecutor(), drm) {
@Override
@ -338,16 +365,21 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
}
@Override
protected void handleFailure() {
// Bug234289: If memory read fails, return a block marked as invalid
MemoryByte[] block = new MemoryByte[word_size * count];
for (int i = 0; i < block.length; i++)
block[i] = new MemoryByte((byte) 0, (byte) 0);
drm.setData(block);
drm.setData(createInvalidBlock(word_size * count));
drm.done();
}
}
);
);
}
}
private MemoryByte[] createInvalidBlock(int size) {
// Bug234289: If memory read fails, return a block marked as invalid
MemoryByte[] block = new MemoryByte[size];
for (int i = 0; i < block.length; i++)
block[i] = new MemoryByte((byte) 0, (byte) 0);
return block;
}
/**
* @param memoryDMC

View file

@ -10,6 +10,7 @@
* ENEA Software AB - CLI command extension - fix for bug 190277
* Ericsson - Implementation for DSF-GDB
* Anna Dushistova (Mentor Graphics) - [318322] Add set solib-absolute-prefix
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command;
@ -57,6 +58,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataEvaluateExpression;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataListRegisterNames;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataListRegisterValues;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataReadMemory;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataReadMemoryBytes;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataWriteMemory;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnvironmentCD;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnvironmentDirectory;
@ -94,6 +96,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBShowExitCode;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInferiorTTYSet;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExec;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExecConsole;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIListFeatures;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIListThreadGroups;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIRemoveInferior;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIStackInfoDepth;
@ -145,10 +148,12 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIDataDisassembleInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataEvaluateExpressionInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterValuesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataReadMemoryBytesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataReadMemoryInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataWriteMemoryInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIGDBShowExitCodeInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIStackInfoDepthInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIStackListArgumentsInfo;
@ -358,6 +363,12 @@ public class CommandFactory {
return new MIDataReadMemory(ctx, offset, address, word_format, word_size, rows, cols, asChar);
}
/** @since 4.0 */
public ICommand<MIDataReadMemoryBytesInfo> createMIDataReadMemoryBytes(IDMContext ctx, String address,
long offset, int num_bytes) {
return new MIDataReadMemoryBytes(ctx, address, offset, num_bytes);
}
public ICommand<MIDataWriteMemoryInfo> createMIDataWriteMemory(IDMContext ctx, long offset, String address,
int wordFormat, int wordSize, String value) {
return new MIDataWriteMemory(ctx, offset, address, wordFormat, wordSize, value);
@ -588,6 +599,11 @@ public class CommandFactory {
return new MIInterpreterExecConsole<MIInfo>(ctx, cmd);
}
/** @since 4.0 */
public ICommand<MIListFeaturesInfo> createMIListFeatures(ICommandControlDMContext ctx) {
return new MIListFeatures(ctx);
}
public ICommand<MIListThreadGroupsInfo> createMIListThreadGroups(ICommandControlDMContext ctx) {
return new MIListThreadGroups(ctx);
}

View file

@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2010 CodeSourcery 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:
* Vladimir Prus (CodeSourcery) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataReadMemoryBytesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
/**
* -data-read-memory-bytes [ -o BYTE-OFFSET ]
* ADDRESS COUNT
* where:
*
* `ADDRESS'
* An expression specifying the address of the first memory word to be
* read. Complex expressions containing embedded white space should
* be quoted using the C convention.
*
* `COUNT'
* The number of bytes to read. This should be an integer literal.
*
* `BYTE-OFFSET'
* The offsets in bytes relative to ADDRESS at which to start
* reading. This should be an integer literal. This option is
* provided so that a frontend is not required to first evaluate
* address and then perform address arithmetics itself.
* @since 4.0
*/
public class MIDataReadMemoryBytes extends MICommand<MIDataReadMemoryBytesInfo> {
private int fSize;
public MIDataReadMemoryBytes(IDMContext ctx, String address, long offset,
int num_bytes) {
super(ctx, "-data-read-memory-bytes"); //$NON-NLS-1$
fSize = num_bytes;
if (offset != 0) {
setOptions(new String[] { "-o", Long.toString(offset) }); //$NON-NLS-1$
}
setParameters(new String[] { address, Integer.toString(num_bytes) });
}
@Override
public MIDataReadMemoryBytesInfo getResult(MIOutput out) {
return new MIDataReadMemoryBytesInfo(out, fSize);
}
}

View file

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2010 CodeSourcery 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:
* Vladimir Prus (CodeSourcery) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
/**
* -list-features
*
* Returns a list of particular features of the MI protocol that this
* version of gdb implements. A feature can be a command, or a new field
* in an output of some command, or even an important bugfix. While a
* frontend can sometimes detect presence of a feature at runtime, it is
* easier to perform detection at debugger startup.
*
* The command returns a list of strings, with each string naming an
* available feature. Each returned string is just a name, it does not
* have any internal structure.
* @since 4.0
*/
public class MIListFeatures extends MICommand<MIListFeaturesInfo> {
public MIListFeatures(ICommandControlDMContext ctx) {
super(ctx, "-list-features"); //$NON-NLS-1$
}
@Override
public MIListFeaturesInfo getResult(MIOutput out) {
return new MIListFeaturesInfo(out);
}
}

View file

@ -0,0 +1,92 @@
/*******************************************************************************
* Copyright (c) 2010 CodeSourcery 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:
* Vladimir Prus (CodeSourcery) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
import org.eclipse.debug.core.model.MemoryByte;
/**
* Example output is:
*
* (gdb)
* -data-read-memory-bytes &a 10
* ^done,memory=[{begin="0xbffff154",offset="0x00000000",
* end="0xbffff15e",
* contents="01000000020000000300"}]
* @since 4.0
*/
public class MIDataReadMemoryBytesInfo extends MIInfo {
/* The cached memory block. */
private MemoryByte[] fBlock = null;
public MIDataReadMemoryBytesInfo(MIOutput output, int size) {
super(output);
parse(size);
}
/**
* Return the memory block
*/
public MemoryByte[] getMIMemoryBlock() {
return fBlock;
}
private void parse(int size)
{
fBlock = new MemoryByte[size];
// Fill the block with invalid bytes, initially.
for (int i = 0; i < size; i++)
fBlock[i] = new MemoryByte((byte) 0, (byte) 0);
MIResult[] results = getMIOutput().getMIResultRecord().getMIResults();
for (int i = 0; i < results.length; i++) {
if (results[i].getVariable().equals("memory")) //$NON-NLS-1$
{
MIList v = (MIList) (results[i].getMIValue());
try {
for (int j = 0; j < v.getMIValues().length; ++j) {
MITuple b = (MITuple) (v.getMIValues()[j]);
int offset = 0;
String contents = ""; //$NON-NLS-1$
for (int k = 0; k < b.getMIResults().length; ++k) {
MIResult r = b.getMIResults()[k];
if (r.getVariable().equals("offset")) //$NON-NLS-1$
{
String offset_s = ((MIConst) r.getMIValue())
.getCString();
offset = Integer.decode(offset_s);
} else if (r.getVariable().equals("contents")) //$NON-NLS-1$
{
contents = ((MIConst) r.getMIValue()).getCString();
}
}
if (offset + contents.length()/2 <= size)
for (int k = 0; k < contents.length() / 2; ++k) {
fBlock[offset + k] = new MemoryByte(
(byte) Integer.parseInt(
contents.substring(k * 2, k * 2 + 2),
16));
}
}
}
catch(NumberFormatException e)
{
// Something went wrong. Stop processing this memory range.
}
}
}
}
}

View file

@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2010 CodeSourcery 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:
* Vladimir Prus (CodeSourcery) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
import java.util.ArrayList;
import java.util.List;
/**
* Example output is:
*
* (gdb) -list-features
* ^done,result=["feature1","feature2"]
* @since 4.0
*/
public class MIListFeaturesInfo extends MIInfo {
private List<String> fFeatures = new ArrayList<String>();
public MIListFeaturesInfo(MIOutput out) {
super(out);
parse();
}
public List<String> getFeatures() {
return fFeatures;
}
private void parse() {
if (isDone()) {
MIOutput out = getMIOutput();
MIResultRecord rr = out.getMIResultRecord();
if (rr != null) {
MIResult[] results = rr.getMIResults();
for (int i = 0; i < results.length; i++) {
String var = results[i].getVariable();
if (var.equals("features")) { //$NON-NLS-1$
MIValue val = results[i].getMIValue();
if (val instanceof MIList) {
MIList list = (MIList) val;
for (int j = 0; j < list.getMIValues().length; ++j) {
MIValue feature = list.getMIValues()[j];
if (feature instanceof MIConst)
fFeatures.add(((MIConst) feature).getString());
}
}
}
}
}
}
}
}