diff options
author | Baha El Kassaby | 2018-05-02 19:52:39 +0000 |
---|---|---|
committer | Jonah Graham | 2019-11-25 17:01:21 +0000 |
commit | 949efc65727a2db644b0436f4df3a203a904fceb (patch) | |
tree | 4ab0c044275a35dd19c59c3c1767f385e9c5afaf /dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org | |
parent | 7e267a47915bb79d384528be5be713e6fd3c10fd (diff) | |
download | org.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')
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$ + } + + } +} |