From cb2b5e568790262deeb4f03fcb8a6f7f88c8031b Mon Sep 17 00:00:00 2001 From: Alexandre Montplaisir Date: Tue, 22 Mar 2016 21:37:36 -0400 Subject: [PATCH] lttng.ust: Implement a symbol provider for LTTng-UST traces This new symbol provider will make use of the "Debug Info" analysis, which means it will only be available for traces taken with LTTng-UST >= 2.8. It will call into the existing BinaryCallsite and SourceCallsite aspects to get the function name of a given address. The provider's configuration page will allow specifying the "root directory" of a target image. This is useful in cases where a trace is taken on a remote target, and an image of that target is available locally. Since paths are found directly in the trace, this means that a trace with the proper information taken on the same system should show the function names in the Callstack View without the need for the user to configure anything! Possible future improvements: - Split the symbol provider extension point in core and ui parts - Merge the FileOffsetMapper logic with the core parts of the symbol provider. - Move the "current path prefix" configuration from the trace object to the core symbol provider. References bug 484042 Change-Id: Ia346c1eab2b54a54ddf672c7ffafd0655a47ee34 Signed-off-by: Alexandre Montplaisir Reviewed-on: https://git.eclipse.org/r/69973 Reviewed-by: Hudson CI Reviewed-by: Matthew Khouzam Tested-by: Matthew Khouzam --- .../debuginfo/UstDebugInfoBinaryAspect.java | 42 +++- .../debuginfo/UstDebugInfoSourceAspect.java | 30 ++- .../lttng2/ust/core/trace/LttngUstTrace.java | 92 +++++++++ .../META-INF/MANIFEST.MF | 1 + .../plugin.xml | 8 + .../ust/ui/analysis/debuginfo/Messages.java | 44 ++++ .../debuginfo/UstDebugInfoSymbolProvider.java | 79 +++++++ .../UstDebugInfoSymbolProviderFactory.java | 43 ++++ ...DebugInfoSymbolProviderPreferencePage.java | 194 ++++++++++++++++++ .../ui/analysis/debuginfo/messages.properties | 23 +++ .../ui/analysis/debuginfo/package-info.java | 11 + .../symbols/BasicSymbolProviderFactory.java | 4 +- .../ui/symbols/ISymbolProviderFactory.java | 3 +- 13 files changed, 561 insertions(+), 13 deletions(-) create mode 100644 lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/Messages.java create mode 100644 lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProvider.java create mode 100644 lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderFactory.java create mode 100644 lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderPreferencePage.java create mode 100644 lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/messages.properties create mode 100644 lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/package-info.java diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoBinaryAspect.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoBinaryAspect.java index c2fc6206bb..4bb345e2dd 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoBinaryAspect.java +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoBinaryAspect.java @@ -53,8 +53,9 @@ public class UstDebugInfoBinaryAspect implements ITmfEventAspect if (!(event.getTrace() instanceof LttngUstTrace)) { return null; } + LttngUstTrace trace = (LttngUstTrace) event.getTrace(); - ILttngUstEventLayout layout = ((LttngUstTrace) event.getTrace()).getEventLayout(); + ILttngUstEventLayout layout = trace.getEventLayout(); /* We need both the vpid and ip contexts */ ITmfEventField vpidField = event.getContent().getField(layout.contextVpid()); @@ -64,13 +65,33 @@ public class UstDebugInfoBinaryAspect implements ITmfEventAspect } Long vpid = (Long) vpidField.getValue(); Long ip = (Long) ipField.getValue(); + long ts = event.getTimestamp().toNanos(); + return getBinaryCallsite(trace, vpid.intValue(), ts, ip.longValue()); + } + + /** + * Get the binary callsite (which means binary file and offset in this file) + * corresponding to the given instruction pointer, for the given PID and + * timetamp. + * + * @param trace + * The trace, from which we will get the debug info analysis + * @param pid + * The PID for which we want the symbol + * @param ts + * The timestamp of the query + * @param ip + * The instruction pointer address + * @return The {@link BinaryCallsite} object with the relevant information + */ + public static @Nullable BinaryCallsite getBinaryCallsite(LttngUstTrace trace, int pid, long ts, long ip) { /* * First match the IP to the correct binary or library, by using the * UstDebugInfoAnalysis. */ UstDebugInfoAnalysisModule module = - TmfTraceUtils.getAnalysisModuleOfClass(event.getTrace(), + TmfTraceUtils.getAnalysisModuleOfClass(trace, UstDebugInfoAnalysisModule.class, UstDebugInfoAnalysisModule.ID); if (module == null) { /* @@ -79,27 +100,29 @@ public class UstDebugInfoBinaryAspect implements ITmfEventAspect */ return null; } - long ts = event.getTimestamp().getValue(); - UstDebugInfoLoadedBinaryFile file = module.getMatchingFile(ts, vpid, ip); + UstDebugInfoLoadedBinaryFile file = module.getMatchingFile(ts, pid, ip); if (file == null) { return null; } + /* Apply the path prefix defined by the trace, if any */ + String fullPath = (trace.getSymbolProviderConfig().getActualRootDirPath() + file.getFilePath()); + long offset; - if (isPIC(file)) { - offset = (ip.longValue() - file.getBaseAddress()); + if (isPIC(fullPath)) { + offset = (ip - file.getBaseAddress()); } else { /* * In the case of the object being the main binary (loaded at a very * low address), we must pass the actual ip address to addr2line. */ - offset = ip.longValue(); + offset = ip; } // TODO If the binary is present on the current file system, we could // try to get the symbol name from it. - return new BinaryCallsite(file.getFilePath(), EMPTY_STRING, offset); + return new BinaryCallsite(fullPath, EMPTY_STRING, offset); } /** @@ -107,13 +130,12 @@ public class UstDebugInfoBinaryAspect implements ITmfEventAspect * or not. This indicates if addr2line considers the addresses as absolute * addresses or as offsets. */ - private static boolean isPIC(UstDebugInfoLoadedBinaryFile file) { + private static boolean isPIC(String filePath) { /* * Ghetto binary/library identification for now. It would be possible to * parse the ELF binary to check if it is position-independent * (-fPIC/-fPIE) or not. */ - String filePath = file.getFilePath(); return (filePath.endsWith(".so") || filePath.contains(".so.")); //$NON-NLS-1$ //$NON-NLS-2$ } diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoSourceAspect.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoSourceAspect.java index 8f947bcf80..fbeed9c476 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoSourceAspect.java +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoSourceAspect.java @@ -52,6 +52,7 @@ public class UstDebugInfoSourceAspect implements ITmfEventAspect { if (!(event.getTrace() instanceof LttngUstTrace)) { return null; } + LttngUstTrace trace = (LttngUstTrace) event.getTrace(); /* * Resolve the binary callsite first, from there we can use the file's @@ -62,6 +63,21 @@ public class UstDebugInfoSourceAspect implements ITmfEventAspect { return null; } + return getSourceCallsite(trace, bc); + } + + /** + * Get the source callsite (the full {@link TmfCallsite} information) from a + * binary callsite. + * + * @param trace + * The trace, which may contain trace-specific configuration + * @param bc + * The binary callsite + * @return The source callsite, which sould include file name, function name + * and line number + */ + public static @Nullable TmfCallsite getSourceCallsite(LttngUstTrace trace, BinaryCallsite bc) { Iterable callsites = FileOffsetMapper.getCallsiteFromOffset(new File(bc.getBinaryFilePath()), bc.getOffset()); if (callsites == null || Iterables.isEmpty(callsites)) { @@ -72,6 +88,18 @@ public class UstDebugInfoSourceAspect implements ITmfEventAspect { * We will take the "deepest" one in the stack, which should refer to * the initial, non-inlined location. */ - return Iterables.getLast(callsites); + TmfCallsite callsite = Iterables.getLast(callsites); + + /* + * Apply the path prefix again, this time on the path given from + * addr2line. If applicable. + */ + String pathPrefix = trace.getSymbolProviderConfig().getActualRootDirPath(); + if (pathPrefix.isEmpty()) { + return callsite; + } + + String fullFileName = (pathPrefix + callsite.getFileName()); + return new TmfCallsite(fullFileName, callsite.getFunctionName(), callsite.getLineNumber()); } } diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/trace/LttngUstTrace.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/trace/LttngUstTrace.java index 32bf54e99e..de923a12ec 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/trace/LttngUstTrace.java +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/trace/LttngUstTrace.java @@ -145,4 +145,96 @@ public class LttngUstTrace extends CtfTmfTrace { } return status; } + + // ------------------------------------------------------------------------ + // Fields/methods bridging the Debug-info symbol provider + // ------------------------------------------------------------------------ + + /* + * FIXME Once the symbol provider is split in core/ui components, the + * UstDebugInfoSymbolProvider should be moved to the core plugin, and this + * here can be removed. + */ + + /** + * Configuration of the symbol provider. + * + * @since 2.0 + */ + public static class SymbolProviderConfig { + + private final boolean fUseCustomRootDir; + private final @NonNull String fCustomRootDirPath; + + /** + * Constructor + * + * Note that a path can be specified even if 'useCustomRootDir' is + * false. This will keep the setting in the text field even when it is + * grayed out. + * + * @param useCustomRootDir + * Should a custom directory be used + * @param rootDirPath + * Custom directory path + */ + public SymbolProviderConfig(boolean useCustomRootDir, @NonNull String rootDirPath) { + fUseCustomRootDir = useCustomRootDir; + fCustomRootDirPath = rootDirPath; + } + + /** + * @return Should a custom directory be used + */ + public boolean useCustomRootDir() { + return fUseCustomRootDir; + } + + /** + * @return The configured root directory + */ + public String getCustomRootDirPath() { + return fCustomRootDirPath; + } + + /** + * Return the "real" path to use for symbol resolution. This is a + * convenience method that avoids having to check the state of + * {@link #useCustomRootDir()} separately. + * + * @return The actual root directory to use + */ + public String getActualRootDirPath() { + if (fUseCustomRootDir) { + return fCustomRootDirPath; + } + return ""; //$NON-NLS-1$ + } + } + + private @NonNull SymbolProviderConfig fCurrentProviderConfig = + /* Default settings for new traces */ + new SymbolProviderConfig(false, ""); //$NON-NLS-1$ + + + /** + * Get the current symbol provider configuration for this trace. + * + * @return The current symbol provider configuration + * @since 2.0 + */ + public @NonNull SymbolProviderConfig getSymbolProviderConfig() { + return fCurrentProviderConfig; + } + + /** + * Set the symbol provider configuration for this trace. + * + * @param config + * The new symbol provider configuration to use + * @since 2.0 + */ + public void setSymbolProviderConfig(@NonNull SymbolProviderConfig config) { + fCurrentProviderConfig = config; + } } diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/META-INF/MANIFEST.MF b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/META-INF/MANIFEST.MF index d5c9704e77..c4154ad14d 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/META-INF/MANIFEST.MF +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/META-INF/MANIFEST.MF @@ -18,6 +18,7 @@ Require-Bundle: org.eclipse.core.resources, org.eclipse.tracecompass.tmf.ctf.core Export-Package: org.eclipse.tracecompass.internal.lttng2.ust.ui;x-friends:="org.eclipse.tracecompass.lttng2.ust.ui.tests", org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.callstack;x-friends:="org.eclipse.tracecompass.lttng2.ust.ui.tests", + org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.debuginfo;x-internal:=true, org.eclipse.tracecompass.internal.lttng2.ust.ui.views.memusage;x-friends:="org.eclipse.tracecompass.lttng2.ust.ui.tests,org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests", org.eclipse.tracecompass.lttng2.ust.ui.analysis.callstack Import-Package: com.google.common.base, diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/plugin.xml b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/plugin.xml index 7abcd7192e..801eb4b559 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/plugin.xml +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/plugin.xml @@ -39,4 +39,12 @@ + + + + diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/Messages.java b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/Messages.java new file mode 100644 index 0000000000..30a2865ba7 --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/Messages.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. 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 + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.debuginfo; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.osgi.util.NLS; + +/** + * Message bundle + * + * @noreference Messages class + */ +@NonNullByDefault({}) +@SuppressWarnings("javadoc") +public class Messages extends NLS { + + private Messages() {} + + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.debuginfo.messages"; //$NON-NLS-1$ + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + public static String PreferencePage_WindowDescription; + + public static String PreferencePage_CheckboxLabel; + public static String PreferencePage_CheckboxTooltip; + + public static String PreferencePage_ButtonBrowse; + public static String PreferencePage_ButtonClear; + + public static String PreferencePage_BrowseDialogTitle; + public static String PreferencePage_ErrorDirectoryDoesNotExists; + +} diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProvider.java b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProvider.java new file mode 100644 index 0000000000..8ca91fd2a3 --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProvider.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. 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 + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.debuginfo; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.BinaryCallsite; +import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoAnalysisModule; +import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoBinaryAspect; +import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoSourceAspect; +import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace; +import org.eclipse.tracecompass.tmf.core.event.lookup.TmfCallsite; +import org.eclipse.tracecompass.tmf.ui.symbols.DefaultSymbolProvider; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderPreferencePage; + +/** + * Symbol provider for UST traces with debug information. + * + * @author Alexandre Montplaisir + * @see UstDebugInfoAnalysisModule + */ +public class UstDebugInfoSymbolProvider extends DefaultSymbolProvider { + + /** + * Create a new {@link UstDebugInfoSymbolProvider} for the given trace + * + * @param trace + * A non-null trace + */ + public UstDebugInfoSymbolProvider(LttngUstTrace trace) { + super(trace); + } + + /** + * Sets the configured path prefix. Usually called from the preferences + * page. + * + * @param newPathPrefix + * The new path prefix to use + */ + void setConfiguredPathPrefix(LttngUstTrace.SymbolProviderConfig newConfig) { + getTrace().setSymbolProviderConfig(newConfig); + } + + @Override + public @NonNull LttngUstTrace getTrace() { + /* Type enforced at constructor */ + return (LttngUstTrace) super.getTrace(); + } + + @Override + public @Nullable String getSymbolText(int pid, long timestamp, long address) { + TmfCallsite callsite = getSymbolInfo(pid, timestamp, address); + return (callsite == null ? null : callsite.getFunctionName()); + } + + @Override + public @Nullable TmfCallsite getSymbolInfo(int pid, long timestamp, long address) { + BinaryCallsite bc = UstDebugInfoBinaryAspect.getBinaryCallsite(getTrace(), pid, timestamp, address); + if (bc == null) { + return null; + } + + return UstDebugInfoSourceAspect.getSourceCallsite(getTrace(), bc); + } + + @Override + public @NonNull ISymbolProviderPreferencePage createPreferencePage() { + return new UstDebugInfoSymbolProviderPreferencePage(this); + } + +} diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderFactory.java b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderFactory.java new file mode 100644 index 0000000000..c43126dda7 --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderFactory.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. 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 + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.debuginfo; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoAnalysisModule; +import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderFactory; + +/** + * Factory to create {@link UstDebugInfoSymbolProvider}. Provided to TMF via + * the extension point. Only works with LTTng-UST traces. + * + * @author Alexandre Montplaisir + */ +public class UstDebugInfoSymbolProviderFactory implements ISymbolProviderFactory { + + @Override + public @Nullable ISymbolProvider createProvider(ITmfTrace trace) { + /* + * This applies only to UST traces that fulfill the DebugInfo analysis + * requirements. + */ + UstDebugInfoAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, + UstDebugInfoAnalysisModule.class, UstDebugInfoAnalysisModule.ID); + + if (module != null && trace instanceof LttngUstTrace) { + return new UstDebugInfoSymbolProvider((LttngUstTrace) trace); + } + return null; + } + +} diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderPreferencePage.java b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderPreferencePage.java new file mode 100644 index 0000000000..5fdac6253a --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/UstDebugInfoSymbolProviderPreferencePage.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. 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 + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.debuginfo; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; +import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace; +import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace.SymbolProviderConfig; +import org.eclipse.tracecompass.tmf.ui.symbols.AbstractSymbolProviderPreferencePage; + +/** + * Preference page to configure a path prefix from which to resolve all the + * paths found the binary file's debug information. + * + * @author Alexandre Montplaisir + */ +public class UstDebugInfoSymbolProviderPreferencePage extends AbstractSymbolProviderPreferencePage { + + private @Nullable Button fUseCustomDirectoryCheckbox; + private @Nullable Text fCustomDirectoryPath; + private @Nullable Button fBrowseButton; + private @Nullable Button fClearButton; + + /** + * Creates a new object for the given provider + * + * @param provider + * a non-null provider + */ + public UstDebugInfoSymbolProviderPreferencePage(UstDebugInfoSymbolProvider provider) { + super(provider); + setDescription(MessageFormat.format(Messages.PreferencePage_WindowDescription, provider.getTrace().getName())); + setValid(true); + } + + @Override + public UstDebugInfoSymbolProvider getSymbolProvider() { + /* Type enforced at constructor */ + return (UstDebugInfoSymbolProvider) super.getSymbolProvider(); + } + + @Override + protected Control createContents(@Nullable Composite parent) { + /* + * We will use a grid layout with 3 columns : + * + * [checkbox+label][][] + * + * [text field][Browse][Clear] + */ + Composite composite = new Composite(parent, SWT.BORDER); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + composite.setLayout(new GridLayout(3, false)); + + /* The first row: checkbox and itslabel */ + Button checkBox = new Button(composite, SWT.CHECK); + checkBox.setText(Messages.PreferencePage_CheckboxLabel); + checkBox.setToolTipText(Messages.PreferencePage_CheckboxTooltip); + checkBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(@Nullable SelectionEvent e) { + updateContents(); + } + }); + fUseCustomDirectoryCheckbox = checkBox; + + /* Nothing in the two following cells */ + new Label(composite, SWT.NONE); + new Label(composite, SWT.NONE); + + /* Second row: The text input box */ + Text text = new Text(composite, SWT.BORDER); + text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + text.setEditable(false); + text.setToolTipText(Messages.PreferencePage_CheckboxTooltip); + fCustomDirectoryPath = text; + + /* The "Browse..." button */ + Button browseButton = new Button(composite, SWT.NONE); + browseButton.setText(Messages.PreferencePage_ButtonBrowse); + browseButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(@Nullable SelectionEvent e) { + browseDirectory(checkNotNull(fCustomDirectoryPath), Messages.PreferencePage_BrowseDialogTitle); + } + }); + fBrowseButton = browseButton; + + /* The "Clear" button */ + Button clearButton = new Button(composite, SWT.NONE); + clearButton.setText(Messages.PreferencePage_ButtonClear); + clearButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(@Nullable SelectionEvent e) { + checkNotNull(fCustomDirectoryPath).setText(""); //$NON-NLS-1$ + updateContents(); + } + }); + fClearButton = clearButton; + + /* Load existing preferences */ + loadCurrentSettings(); + + return composite; + } + + private void browseDirectory(Text textField, @Nullable String dialogTitle) { + DirectoryDialog dialog = new DirectoryDialog(getShell()); + dialog.setText(dialogTitle); + String dirPath = dialog.open(); + if (dirPath != null) { + textField.setText(dirPath); + updateContents(); + } + } + + private void loadCurrentSettings() { + /* The settings are currently stored in the trace object */ + LttngUstTrace trace = getSymbolProvider().getTrace(); + SymbolProviderConfig config = trace.getSymbolProviderConfig(); + + checkNotNull(fUseCustomDirectoryCheckbox).setSelection(config.useCustomRootDir()); + checkNotNull(fCustomDirectoryPath).setText(config.getCustomRootDirPath()); + + updateContents(); + } + + @Override + public void saveConfiguration() { + SymbolProviderConfig config = + new SymbolProviderConfig(getCurrentCheckBoxState(), getCurrentPathPrefix()); + + LttngUstTrace trace = getSymbolProvider().getTrace(); + trace.setSymbolProviderConfig(config); + } + + private boolean getCurrentCheckBoxState() { + return (checkNotNull(fUseCustomDirectoryCheckbox).getSelection()); + } + + private String getCurrentPathPrefix() { + return nullToEmptyString(checkNotNull(fCustomDirectoryPath).getText()); + } + + /** + * Grey out the relevant controls if the checkbox is unchecked, and vice + * versa. Also verify if the current settings are valid, and update the + * window error message if needed. + */ + private void updateContents() { + boolean useCustomDirEnabled = getCurrentCheckBoxState(); + checkNotNull(fCustomDirectoryPath).setEnabled(useCustomDirEnabled); + checkNotNull(fBrowseButton).setEnabled(useCustomDirEnabled); + checkNotNull(fClearButton).setEnabled(useCustomDirEnabled); + + String errorMessage = null; + + if (useCustomDirEnabled) { + String pathPrefix = getCurrentPathPrefix(); + Path path = Paths.get(pathPrefix); + if (pathPrefix.equals("") || !Files.isDirectory(path)) { //$NON-NLS-1$ + errorMessage = Messages.PreferencePage_ErrorDirectoryDoesNotExists; + } + } + setErrorMessage(errorMessage); + setValid(errorMessage == null); + } + +} diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/messages.properties b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/messages.properties new file mode 100644 index 0000000000..5f340657e4 --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/messages.properties @@ -0,0 +1,23 @@ +############################################################################### +# Copyright (c) 2016 EfficiOS Inc. 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 +############################################################################### + +PreferencePage_WindowDescription=Multi-binary symbol mapping configuration for LTTng-UST 2.8+ trace "{0}" + +PreferencePage_CheckboxLabel = Use custom target root directory +PreferencePage_CheckboxTooltip = \ +By default, paths to binaries and libraries found in the trace will be resolved as-is on the current system.\n\ +You can specify a path here to use as a \"prefix\" for all path resolutions.\n\ +For example, if the trace comes from a different target, and you have a local \ +image of the binaries of that target, you can specify the root location of this image here. + +PreferencePage_ButtonBrowse = Browse... +PreferencePage_ButtonClear = Clear + +PreferencePage_BrowseDialogTitle=Select a target root directory +PreferencePage_ErrorDirectoryDoesNotExists=The current path is missing or is not a directory. diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/package-info.java b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/package-info.java new file mode 100644 index 0000000000..5ca65d54af --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui/src/org/eclipse/tracecompass/internal/lttng2/ust/ui/analysis/debuginfo/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. 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 + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.lttng2.ust.ui.analysis.debuginfo; diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderFactory.java index 860d607b02..6fc01be3ab 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderFactory.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderFactory.java @@ -10,6 +10,7 @@ package org.eclipse.tracecompass.internal.tmf.ui.symbols; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider; @@ -26,7 +27,8 @@ import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderFactory; public class BasicSymbolProviderFactory implements ISymbolProviderFactory { @Override - public ISymbolProvider createProvider(ITmfTrace trace) { + public @NonNull ISymbolProvider createProvider(ITmfTrace trace) { + /* This provider can apply to any trace */ return new BasicSymbolProvider(trace); } diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderFactory.java index 217c4cd0b2..6d1cefc1ac 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderFactory.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderFactory.java @@ -11,6 +11,7 @@ package org.eclipse.tracecompass.tmf.ui.symbols; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; /** @@ -33,6 +34,6 @@ public interface ISymbolProviderFactory { * @return A newly created provider that can resolve symbols from the given * trace or null if no such provider can be created by this factory */ - ISymbolProvider createProvider(@NonNull ITmfTrace trace); + @Nullable ISymbolProvider createProvider(@NonNull ITmfTrace trace); } -- 2.34.1