Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaha El Kassaby2018-05-02 19:52:39 +0000
committerJonah Graham2019-11-25 17:01:21 +0000
commit949efc65727a2db644b0436f4df3a203a904fceb (patch)
tree4ab0c044275a35dd19c59c3c1767f385e9c5afaf /dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org
parent7e267a47915bb79d384528be5be713e6fd3c10fd (diff)
downloadorg.eclipse.cdt-949efc65727a2db644b0436f4df3a203a904fceb.tar.gz
org.eclipse.cdt-949efc65727a2db644b0436f4df3a203a904fceb.tar.xz
org.eclipse.cdt-949efc65727a2db644b0436f4df3a203a904fceb.zip
Bug 530443: Add support for "info sources" MI equivalent
*Implementation of -file-list-exec-source-files MI command. *Add new Debug Sources view with tree-like structure Change-Id: I6e734799712c059c8e53aa882777dfebd85aa0d5 Also-by: Jonah Graham <jonah@kichwacoders.com> Signed-off-by: Baha El Kassaby <baha.elkassaby@gmail.com>
Diffstat (limited to 'dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org')
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBSourceLookup.java157
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IDebugSourceFiles.java67
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java7
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIFileListExecSourceFiles.java39
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MiSourceFilesInfo.java164
5 files changed, 415 insertions, 19 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBSourceLookup.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBSourceLookup.java
index 3a292ea7953..739f4e9f1e5 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBSourceLookup.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBSourceLookup.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015, 2016 Kichwa Coders and others.
+ * Copyright (c) 2015, 2018 Kichwa Coders and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,10 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
@@ -24,13 +28,19 @@ import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
-import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+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.launching.GdbSourceLookupDirector;
import org.eclipse.cdt.dsf.mi.service.CSourceLookup;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MiSourceFilesInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MiSourceFilesInfo.SourceFileInfo;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@@ -40,9 +50,16 @@ import org.eclipse.core.runtime.Status;
*
* @since 5.0
*/
-public class GDBSourceLookup extends CSourceLookup implements IGDBSourceLookup {
+public class GDBSourceLookup extends CSourceLookup implements IGDBSourceLookup, IDebugSourceFiles, ICachingService {
- private ICommandControl fCommand;
+ private static class DebugSourceFilesChangedEvent extends AbstractDMEvent<IDMContext>
+ implements IDebugSourceFilesChangedEvent {
+ public DebugSourceFilesChangedEvent(IDMContext context) {
+ super(context);
+ }
+ }
+
+ private ICommandControlService fCommand;
private CommandFactory fCommandFactory;
private Map<ISourceLookupDMContext, CSourceLookupDirector> fDirectors = new HashMap<>();
/**
@@ -50,6 +67,8 @@ public class GDBSourceLookup extends CSourceLookup implements IGDBSourceLookup {
*/
private Map<String, String> fCachedEntries = Collections.emptyMap();
+ private CommandCache fDebugSourceFilesCache;
+
public GDBSourceLookup(DsfSession session) {
super(session);
}
@@ -65,12 +84,14 @@ public class GDBSourceLookup extends CSourceLookup implements IGDBSourceLookup {
}
private void doInitialize(RequestMonitor rm) {
- fCommand = getServicesTracker().getService(ICommandControl.class);
+ fCommand = getServicesTracker().getService(ICommandControlService.class);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
- register(new String[] { IGDBSourceLookup.class.getName(), GDBSourceLookup.class.getName() },
- new Hashtable<String, String>());
+ fDebugSourceFilesCache = new CommandCache(getSession(), fCommand);
+ fDebugSourceFilesCache.setContextAvailable(fCommand.getContext(), true);
+ register(new String[] { IGDBSourceLookup.class.getName(), GDBSourceLookup.class.getName(),
+ IDebugSourceFiles.class.getName() }, new Hashtable<String, String>());
rm.done();
}
@@ -120,10 +141,9 @@ public class GDBSourceLookup extends CSourceLookup implements IGDBSourceLookup {
rm.done(false);
} else {
/*
- * Issue the clear and set commands back to back so that the
- * executor thread atomically changes the source lookup settings.
- * Any commands to GDB issued after this call will get the new
- * source substitute settings.
+ * Issue the clear and set commands back to back so that the executor thread
+ * atomically changes the source lookup settings. Any commands to GDB issued
+ * after this call will get the new source substitute settings.
*/
CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) {
@Override
@@ -143,14 +163,19 @@ public class GDBSourceLookup extends CSourceLookup implements IGDBSourceLookup {
fCachedEntries = entries;
CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) {
@Override
- protected void handleFailure() {
- /*
- * We failed to apply the changes. Clear the cache as it does
- * not represent the state of the backend. However we don't have
- * a good recovery here, so on future sourceContainersChanged()
- * calls we will simply reissue the substitutions.
- */
- fCachedEntries = null;
+ protected void handleCompleted() {
+ // Reset the list of source files when source path substitutions change
+ fDebugSourceFilesCache.reset();
+ getSession().dispatchEvent(new DebugSourceFilesChangedEvent(sourceLookupCtx), getProperties());
+ if (!isSuccess()) {
+ /*
+ * We failed to apply the changes. Clear the cache as it does not represent the
+ * state of the backend. However we don't have a good recovery here, so on
+ * future sourceContainersChanged() calls we will simply reissue the
+ * substitutions.
+ */
+ fCachedEntries = null;
+ }
rm.done();
}
};
@@ -160,6 +185,100 @@ public class GDBSourceLookup extends CSourceLookup implements IGDBSourceLookup {
fCommandFactory.createMISetSubstitutePath(sourceLookupCtx, entry.getKey(), entry.getValue()),
new DataRequestMonitor<MIInfo>(getExecutor(), countingRm));
}
+
+ }
+
+ private static final class DebugSourceFileInfo implements IDebugSourceFileInfo {
+ private final SourceFileInfo miInfo;
+
+ private DebugSourceFileInfo(SourceFileInfo miInfo) {
+ if (miInfo == null)
+ throw new IllegalArgumentException("The SourceFileInfo provided is null"); //$NON-NLS-1$
+ this.miInfo = miInfo;
+ }
+
+ @Override
+ public String getName() {
+ // we get the file name without the path
+ String name = miInfo != null ? miInfo.getFile() : null;
+ if (name == null)
+ return name;
+ try {
+ Path p = Paths.get(name);
+ name = p.getFileName() != null ? p.getFileName().toString() : ""; //$NON-NLS-1$
+ } catch (InvalidPathException e) {
+ // do nothing
+ }
+ return name;
+ }
+
+ @Override
+ public String getPath() {
+ // we get the file name without the path
+ String path = miInfo != null ? miInfo.getFullName() : null;
+ if (path == null)
+ return path;
+ try {
+ Path p = Paths.get(path);
+ path = p.toString();
+ } catch (InvalidPathException e) {
+ // do nothing
+ }
+ return path;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((miInfo == null) ? 0 : miInfo.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DebugSourceFileInfo other = (DebugSourceFileInfo) obj;
+ if (miInfo == null) {
+ if (other.miInfo != null)
+ return false;
+ } else if (!miInfo.equals(other.miInfo))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "DebugSourceFileInfo [miInfo=" + miInfo + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
}
+ @Override
+ public void getSources(final IDMContext dmc, final DataRequestMonitor<IDebugSourceFileInfo[]> rm) {
+ fDebugSourceFilesCache.execute(fCommandFactory.createMiFileListExecSourceFiles(dmc),
+ new DataRequestMonitor<MiSourceFilesInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ IDebugSourceFileInfo[] result = null;
+ MiSourceFilesInfo sourceFiles = getData();
+ SourceFileInfo[] info = sourceFiles.getSourceFiles();
+ result = Arrays.asList(info).stream().map(DebugSourceFileInfo::new)
+ .toArray(IDebugSourceFileInfo[]::new);
+ rm.setData(result);
+ rm.done();
+ }
+ });
+ }
+
+ @Override
+ public void flushCache(IDMContext context) {
+ fDebugSourceFilesCache.reset();
+ getSession().dispatchEvent(new DebugSourceFilesChangedEvent(fCommand.getContext()), getProperties());
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IDebugSourceFiles.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IDebugSourceFiles.java
new file mode 100644
index 00000000000..0bd066cc433
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IDebugSourceFiles.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017, 2018 Kichwa Coders and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Jonah Graham (Kichwa Coders) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Provides the ability to obtain the list of source files for the given debug
+ * context. For GDB this is using the -file-list-exec-source-files command
+ *
+ * @since 5.8
+ */
+public interface IDebugSourceFiles extends IDsfService {
+
+ /**
+ * Data type for what is returned by
+ * {@link IDebugSourceFiles#getSources(IDMContext, DataRequestMonitor)}
+ */
+ public interface IDebugSourceFileInfo {
+
+ /**
+ * The name of the source file as it appears in the debug information. This may
+ * be relative, just the name, or absolute. Use {@link #getPath()} for the
+ * absolute path to the file name.
+ *
+ * @return name of the file
+ */
+ public String getName();
+
+ /**
+ * The absolute path of the the file.
+ *
+ * @return path to the file
+ */
+ public String getPath();
+ }
+
+ /**
+ * Event indicating that the list of the files may have changed for the given context.
+ */
+ public interface IDebugSourceFilesChangedEvent extends IDMEvent<IDMContext> {
+ }
+
+ /**
+ * Retrieves the list of sources data/files for the given context.
+ *
+ * @param context
+ * execution context
+ * @param rm
+ * Request completion monitor.
+ */
+ void getSources(IDMContext context, DataRequestMonitor<IDebugSourceFileInfo[]> rm);
+} \ No newline at end of file
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java
index a1aef544584..7e1287d02db 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java
@@ -120,6 +120,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecUncall;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecUntil;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIFileExecAndSymbols;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIFileExecFile;
+import org.eclipse.cdt.dsf.mi.service.command.commands.MIFileListExecSourceFiles;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIFileSymbolFile;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBExit;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSet;
@@ -254,6 +255,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIVarSetFormatInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIVarShowAttributesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIVarShowFormatInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIVarUpdateInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MiSourceFilesInfo;
/**
* Factory to create MI/CLI commands.
@@ -739,6 +741,11 @@ public class CommandFactory {
return new MIFileExecFile(dmc);
}
+ /** @since 5.8*/
+ public ICommand<MiSourceFilesInfo> createMiFileListExecSourceFiles(IDMContext ctx) {
+ return new MIFileListExecSourceFiles(ctx);
+ }
+
public ICommand<MIInfo> createMIFileSymbolFile(ICommandControlDMContext dmc, String file) {
return new MIFileSymbolFile(dmc, file);
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIFileListExecSourceFiles.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIFileListExecSourceFiles.java
new file mode 100644
index 00000000000..c58b4e41e6a
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIFileListExecSourceFiles.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2017, 2018 Kichwa Coders and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Jonah Graham (Kichwa Coders) - 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.MIOutput;
+import org.eclipse.cdt.dsf.mi.service.command.output.MiSourceFilesInfo;
+
+/**
+ *
+ * -file-list-exec-source-files
+ *
+ * Returns the list of source files for the current execution context. It
+ * outputs both filename and full (absolute path) file name of a source file.
+ *
+ * @since 5.8
+ */
+public class MIFileListExecSourceFiles extends MICommand<MiSourceFilesInfo> {
+
+ public MIFileListExecSourceFiles(IDMContext ctx) {
+ super(ctx, "-file-list-exec-source-files"); //$NON-NLS-1$
+ }
+
+ @Override
+ public MiSourceFilesInfo getResult(MIOutput out) {
+ return new MiSourceFilesInfo(out);
+ }
+} \ No newline at end of file
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MiSourceFilesInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MiSourceFilesInfo.java
new file mode 100644
index 00000000000..f1441cfde0a
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MiSourceFilesInfo.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2017, 2018 Kichwa Coders and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Jonah Graham (Kichwa Coders) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.mi.service.command.output;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Example output is:
+ *
+ * <pre>
+ * (gdb) -file-list-exec-source-files
+ * ^done,files=[{file=foo.c,fullname=/home/foo.c},
+ * {file=/home/bar.c,fullname=/home/bar.c},
+ * {file=gdb_could_not_find_fullpath.c}]
+ * </pre>
+ *
+ * @since 5.8
+ */
+public class MiSourceFilesInfo extends MIInfo {
+
+ private SourceFileInfo[] sourceFileInfos;
+
+ public MiSourceFilesInfo(MIOutput record) {
+ super(record);
+ parse();
+ if (sourceFileInfos == null) {
+ sourceFileInfos = new SourceFileInfo[0];
+ }
+ }
+
+ /**
+ * Returns array of source files infos
+ *
+ * @return
+ */
+ public SourceFileInfo[] getSourceFiles() {
+ return sourceFileInfos;
+ }
+
+ 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("files")) { //$NON-NLS-1$
+ MIValue value = results[i].getMIValue();
+ if (value instanceof MIList) {
+ parseResults((MIList) value);
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ private void parseResults(MIList list) {
+ MIValue[] miValues = list.getMIValues();
+ List<SourceFileInfo> infos = new LinkedList<>();
+ if (miValues != null) {
+ for (MIValue miValue : miValues) {
+ if (miValue instanceof MITuple) {
+ MITuple miTuple = (MITuple) miValue;
+ SourceFileInfo info = new SourceFileInfo();
+ info.parse(miTuple.getMIResults());
+ infos.add(info);
+ }
+ }
+ }
+ sourceFileInfos = infos.toArray(new SourceFileInfo[infos.size()]);
+ }
+
+ public static class SourceFileInfo {
+ private String file;
+ private String fullname;
+
+ public void setFile(String file) {
+ this.file = file;
+ }
+
+ public String getFile() {
+ return file;
+ }
+
+ public void setFullName(String fullname) {
+ this.fullname = fullname;
+ }
+
+ public String getFullName() {
+ return fullname;
+ }
+
+ private void parse(MIResult[] results) {
+ for (MIResult result : results) {
+ String variable = result.getVariable();
+ MIValue miVal = result.getMIValue();
+ if (!(miVal instanceof MIConst)) {
+ continue;
+ }
+ String value = ((MIConst) miVal).getCString();
+ switch (variable) {
+ case "file": //$NON-NLS-1$
+ file = value;
+ break;
+ case "fullname": //$NON-NLS-1$
+ fullname = value;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((file == null) ? 0 : file.hashCode());
+ result = prime * result + ((fullname == null) ? 0 : fullname.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SourceFileInfo other = (SourceFileInfo) obj;
+ if (file == null) {
+ if (other.file != null)
+ return false;
+ } else if (!file.equals(other.file))
+ return false;
+ if (fullname == null) {
+ if (other.fullname != null)
+ return false;
+ } else if (!fullname.equals(other.fullname))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "SourceFileInfo [file=" + file + ", fullname=" + fullname + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ }
+}

Back to the top