| /******************************************************************************* |
| * Copyright (c) 2015 Kichwa Coders 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: |
| * Jonah Graham (Kichwa Coders) - initial API and implementation to Add support for gdb's "set substitute-path" (Bug 472765) |
| *******************************************************************************/ |
| package org.eclipse.cdt.dsf.gdb.launching; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.cdt.debug.core.sourcelookup.IMappingSourceContainer; |
| import org.eclipse.cdt.debug.core.sourcelookup.MappingSourceContainer; |
| import org.eclipse.cdt.debug.internal.core.sourcelookup.MapEntrySourceContainer; |
| import org.eclipse.cdt.dsf.debug.sourcelookup.DsfSourceLookupDirector; |
| import org.eclipse.cdt.dsf.gdb.service.IGDBSourceLookup; |
| import org.eclipse.cdt.dsf.service.DsfSession; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.debug.core.sourcelookup.ISourceContainer; |
| import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant; |
| import org.eclipse.debug.core.sourcelookup.containers.DefaultSourceContainer; |
| |
| /** |
| * A Source Lookup director that extends the standard DSF version to support the |
| * GDB backend handling path substitutions using gdb's "set substitute-path" |
| * mechanism. This director works in tandem with {@link IGDBSourceLookup} |
| * service to synchronise GDB's path substitutions. |
| * |
| * @since 5.0 |
| */ |
| public class GdbSourceLookupDirector extends DsfSourceLookupDirector { |
| private final DsfSession fSession; |
| |
| public GdbSourceLookupDirector(DsfSession session) { |
| super(session); |
| fSession = session; |
| } |
| |
| @Override |
| public void initializeParticipants() { |
| /* |
| * We don't call super as we don't want DsfSourceLookupParticipant to be |
| * added explicitly. Instead we use GdbSourceLookupParticipant which |
| * extends DsfSourceLookupParticipant and does not use the mappings |
| * directly but relies on GDB's "set substitute-path". |
| */ |
| addParticipants(new ISourceLookupParticipant[] { new GdbSourceLookupParticipant(fSession) }); |
| } |
| |
| /** |
| * Return a map of substitutions with the Key being the compilation path and |
| * the Value being the machine local path. |
| * |
| * @return map of substitutions |
| */ |
| public Map<String, String> getSubstitutionsPaths() { |
| Map<String, String> entries = new HashMap<>(); |
| collectSubstitutionsPaths(getSourceContainers(), entries); |
| return entries; |
| } |
| |
| protected void collectSubstitutionsPaths(ISourceContainer[] containers, Map<String, String> entries) { |
| for (ISourceContainer container : containers) { |
| if (container instanceof MapEntrySourceContainer) { |
| MapEntrySourceContainer sourceSubContainer = (MapEntrySourceContainer) container; |
| |
| String from = sourceSubContainer.getBackendPathStr(); |
| IPath to = sourceSubContainer.getLocalPath(); |
| if (from != null && to != null) { |
| entries.put(from, to.toOSString()); |
| } |
| } else if (container.isComposite()) { |
| ISourceContainer[] childContainers; |
| try { |
| childContainers = container.getSourceContainers(); |
| } catch (CoreException e) { |
| /* |
| * Consistent with other uses of getSourceContainers, we |
| * silently ignore these children. |
| */ |
| childContainers = new ISourceContainer[0]; |
| } |
| if (container instanceof MappingSourceContainer) { |
| MappingSourceContainer mappingSourceContainer = (MappingSourceContainer) container; |
| if (mappingSourceContainer.isMappingWithBackendEnabled()) { |
| collectSubstitutionsPaths(childContainers, entries); |
| } else { |
| /* |
| * This mapping has explicitly requested *not* to do a |
| * substitute, so don't recurse on children here. |
| */ |
| } |
| } else { |
| /* |
| * There can be MappingSourceContainers in |
| * DefaultSourceContainer, but not in other types of |
| * composite containers (e.g. a DirectorySourceContainer |
| * cannot contain a MappingSourceContainer). |
| * |
| * It is important we don't recurse across all composites |
| * containers for performance reasons. If a |
| * DirectorySourceContainer was recursed here, then it could |
| * means recursing through the entire directory structure |
| * under that container. |
| */ |
| if (container instanceof DefaultSourceContainer) { |
| collectSubstitutionsPaths(childContainers, entries); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Get the compilation path for the given sourceName. Unlike super's |
| * version, for {@link MappingSourceContainer}s where backend mapping is |
| * enabled this method is a no-op as in those cases the backend already |
| * matches. |
| */ |
| @Override |
| public IPath getCompilationPath(String sourceName) { |
| return getCompilationPath(getSourceContainers(), sourceName); |
| } |
| |
| /** |
| * This method mirrors the logic of |
| * {@link #collectSubstitutionsPaths(ISourceContainer[], Map)} on which |
| * containers are iterated and excluded. |
| */ |
| protected IPath getCompilationPath(ISourceContainer[] containers, String sourceName) { |
| for (ISourceContainer container : containers) { |
| |
| if (container instanceof IMappingSourceContainer) { |
| IPath mappedPath = ((IMappingSourceContainer) container).getCompilationPath(sourceName); |
| if (mappedPath != null) { |
| if (container instanceof MappingSourceContainer |
| && ((MappingSourceContainer) container).isMappingWithBackendEnabled()) { |
| /* |
| * This mapping is being handled by GDB backend (i.e. it was |
| * collected by collectSubstitutionsPaths to pass to gdb's |
| * "set substitute-path"). Because GDB is doing the |
| * translation on it, pass the local name to GDB, not the |
| * translated name. |
| */ |
| return new Path(sourceName); |
| } |
| return mappedPath; |
| } |
| } else if (container.isComposite()) { |
| ISourceContainer[] childContainers = null; |
| try { |
| childContainers = container.getSourceContainers(); |
| } catch (CoreException e) { |
| /* |
| * Consistent with other uses of getSourceContainers, we |
| * silently ignore these children. |
| */ |
| } |
| if (childContainers != null) { |
| IPath path = getCompilationPath(childContainers, sourceName); |
| if (path != null) { |
| return path; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| } |