From d90ae2a54951321aadf8e254be0e6df531a63e4f Mon Sep 17 00:00:00 2001 From: Robert Kiss Date: Fri, 26 Feb 2016 18:57:58 +0200 Subject: [PATCH] tmf: Use a symbol provider to locate symbols Contributed symbol provider extension point. Contributed BasicSymbolProvider to symbol provider extension point. Switched CallStackView to symbol provider. Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=487978 Change-Id: Ic40c272c2dbc0074fc170e9ff0d2ee0e9f230559 Signed-off-by: Robert Kiss Reviewed-on: https://git.eclipse.org/r/67442 Reviewed-by: Hudson CI Reviewed-by: Matthew Khouzam Tested-by: Matthew Khouzam Reviewed-by: Alexandre Montplaisir Tested-by: Alexandre Montplaisir --- .../ui/swtbot/tests/CallStackViewTest.java | 5 +- .../plugin.properties | 1 + .../plugin.xml | 9 + ...se.tracecompass.tmf.ui.symbolProvider.exsd | 132 ++++++++++ .../internal/tmf/ui/Messages.java | 23 +- .../internal/tmf/ui/messages.properties | 28 ++- .../tmf/ui/symbols/BasicSymbolProvider.java | 156 ++++++++++++ .../symbols/BasicSymbolProviderFactory.java | 33 +++ .../BasicSymbolProviderPreferencePage.java | 197 +++++++++++++++ .../AbstractSymbolProviderPreferencePage.java | 45 ++++ .../tmf/ui/symbols/DefaultSymbolProvider.java | 88 +++++++ .../tmf/ui/symbols/ISymbolProvider.java | 78 ++++++ .../ui/symbols/ISymbolProviderFactory.java | 38 +++ .../ISymbolProviderPreferencePage.java | 39 +++ .../symbols/SymbolProviderConfigDialog.java | 203 +++++++++++++++ .../tmf/ui/symbols/SymbolProviderManager.java | 139 +++++++++++ .../CallStackPresentationProvider.java | 6 +- .../tmf/ui/views/callstack/CallStackView.java | 231 +++++++++--------- 18 files changed, 1311 insertions(+), 140 deletions(-) create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/schema/org.eclipse.tracecompass.tmf.ui.symbolProvider.exsd create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProvider.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderFactory.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderPreferencePage.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/AbstractSymbolProviderPreferencePage.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/DefaultSymbolProvider.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProvider.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderFactory.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderPreferencePage.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderConfigDialog.java create mode 100644 tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderManager.java diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests/src/org/eclipse/tracecompass/lttng2/ust/ui/swtbot/tests/CallStackViewTest.java b/lttng/org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests/src/org/eclipse/tracecompass/lttng2/ust/ui/swtbot/tests/CallStackViewTest.java index a85851ef22..0e517f8132 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests/src/org/eclipse/tracecompass/lttng2/ust/ui/swtbot/tests/CallStackViewTest.java +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests/src/org/eclipse/tracecompass/lttng2/ust/ui/swtbot/tests/CallStackViewTest.java @@ -100,8 +100,7 @@ public class CallStackViewTest { /** Tooltips of the toolbar buttons */ private static final @NonNull String ALIGN_VIEWS = "Align Views"; - private static final @NonNull String IMPORT_BINARY = "Import a binary file containing debugging symbols"; - private static final @NonNull String IMPORT_TEXT = "Import a text file containing the mapping between addresses and function names"; + private static final @NonNull String CONFIGURE_SYMBOL_PROVIDERS = "Configure how the addresses are mapped to function names"; // Separator private static final @NonNull String SORT_BY_NAME = "Sort threads by thread name"; private static final @NonNull String SORT_BY_ID = "Sort threads by thread id"; @@ -124,7 +123,7 @@ public class CallStackViewTest { // Separator private static final String PIN_VIEW = "Pin View"; private static final List TOOLBAR_BUTTONS_TOOLTIPS = ImmutableList.of( - ALIGN_VIEWS, IMPORT_BINARY, IMPORT_TEXT, + ALIGN_VIEWS, CONFIGURE_SYMBOL_PROVIDERS, "", SORT_BY_NAME, SORT_BY_ID, SORT_BY_START, "", diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties index dc3acfa459..15d90bba7a 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties +++ b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties @@ -16,6 +16,7 @@ Bundle-Name = Trace Compass TMF UI Plug-in # Extension points extensionpoint.trace_type_ui.name = Tmf Trace Type UI Elements extensionpoint.sequence_diagram_loader.name = TMF UML 2 Sequence Diagram Loader +extensionpoint.symbol_provider.name = TMF Symbol provider extension # Perspective and Views names perspective.category.name = Tracing diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml index 530a99bb73..fe60b8acba 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml +++ b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml @@ -3,6 +3,7 @@ + @@ -1964,4 +1965,12 @@ + + + + diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/schema/org.eclipse.tracecompass.tmf.ui.symbolProvider.exsd b/tmf/org.eclipse.tracecompass.tmf.ui/schema/org.eclipse.tracecompass.tmf.ui.symbolProvider.exsd new file mode 100644 index 0000000000..f435ebdf1c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/schema/org.eclipse.tracecompass.tmf.ui.symbolProvider.exsd @@ -0,0 +1,132 @@ + + + + + + + + + This extension point can be used to transform from symbol addresses that might be found inside a TmfTrace into human readable texts, for example function names. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A symbol provider factory can be used to translate symbol addresses that can be found inside traces into symbol names. + + + + + + + The ID of the extension + + + + + + + The name of the class responsible to create an ISymbolProvider + + + + + + + + + + Specify the priority of this factory relativ to the other. It should be an integer number. If not defined or not a valid integer it will be assumed to be zero. + + + + + + + + + + + + 2.0 + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + Since 2.0 + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + Copyright (c) 2016 Movidius 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 <a +href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> + + + + diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Messages.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Messages.java index b860be437b..5ca1d440a5 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Messages.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Messages.java @@ -312,14 +312,9 @@ public class Messages extends NLS { public static String CallStackView_SortByThreadName; public static String CallStackView_SortByThreadId; public static String CallStackView_SortByThreadTime; - public static String CallStackView_ImportMappingButtonText; - public static String CallStackView_ImportMappingButtonTooltip; - public static String CallStackView_ImportMappingDialogTitle; - public static String CallStackView_ImportMappingJobName; - public static String CallStackView_ImportBinaryFileButtonText; - public static String CallStackView_ImportBinaryFileButtonTooltip; - public static String CallStackView_ImportBinaryFileDialogTitle; + public static String CallStackView_ConfigureSymbolProvidersText; + public static String CallStackView_ConfigureSymbolProvidersTooltip; public static String CopyToClipboardOperation_TaskName; public static String CopyToClipboardOperation_OutOfMemoryErrorTitle; @@ -329,6 +324,20 @@ public class Messages extends NLS { public static String ExportToTextJob_Export_trace_to; public static String ExportToTextJob_Unable_to_export_trace; + public static String SymbolProviderConfigDialog_title; + public static String SymbolProviderConfigDialog_message; + + public static String BasicSymbolProviderPrefPage_radioBinaryFile_text; + public static String BasicSymbolProviderPrefPage_radioBinaryFile_tooltip; + public static String BasicSymbolProviderPrefPage_radioMappingFile_text; + public static String BasicSymbolProviderPrefPage_radioMappingFile_tooltip; + public static String BasicSymbolProviderPrefPage_btnBrowse; + public static String BasicSymbolProviderPrefPage_description; + public static String BasicSymbolProviderPrefPage_ImportMappingDialogTitle; + public static String BasicSymbolProviderPrefPage_ImportBinaryFileDialogTitle; + public static String BasicSymbolProviderPrefPage_errorFileDoesNotExists; + public static String BasicSymbolProviderPrefPage_errorSpecifyFile; + public static String BasicSymbolProviderPrefPage_loadingConfigurations; static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/messages.properties b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/messages.properties index 0e5e0c9851..4dbccf37a8 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/messages.properties +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/messages.properties @@ -312,14 +312,9 @@ CallStackView_StackInfoNotAvailable=Stack info not available CallStackView_SortByThreadName=Sort threads by thread name CallStackView_SortByThreadId=Sort threads by thread id CallStackView_SortByThreadTime=Sort threads by start time -CallStackView_ImportMappingButtonText=Import mapping file... -CallStackView_ImportMappingButtonTooltip=Import a text file containing the mapping between addresses and function names -CallStackView_ImportMappingDialogTitle=Select Mapping File -CallStackView_ImportMappingJobName=Updating Call Stack view function mapping -CallStackView_ImportBinaryFileButtonText=Import binary file... -CallStackView_ImportBinaryFileButtonTooltip=Import a binary file containing debugging symbols -CallStackView_ImportBinaryFileDialogTitle=Select Binary File +CallStackView_ConfigureSymbolProvidersText=Configure symbol providers +CallStackView_ConfigureSymbolProvidersTooltip=Configure how the addresses are mapped to function names CopyToClipboardOperation_TaskName=Copying to Clipboard CopyToClipboardOperation_OutOfMemoryErrorTitle=Out Of Memory Error @@ -328,3 +323,22 @@ CopyToClipboardOperation_OutOfMemoryErrorMessage=The full selection cannot be co ExportToTextJob_Export_to=Export to {0}... ExportToTextJob_Export_trace_to=Export trace to {0} ExportToTextJob_Unable_to_export_trace=Unable to export trace to {0} + +#Symbol providers +SymbolProviderConfigDialog_title = Symbol mapping +SymbolProviderConfigDialog_message = Configure how symbols are resolved + +BasicSymbolProviderPrefPage_radioBinaryFile_text=Select a binary file +BasicSymbolProviderPrefPage_radioBinaryFile_tooltip=Select a binary file, executable or library,\nthat was used to produce the selected trace +BasicSymbolProviderPrefPage_radioMappingFile_text=Select a mapping file +BasicSymbolProviderPrefPage_radioMappingFile_tooltip=Select a symbol to address mapping file of the binary used\n\ +to produce the selected trace.\n\ +Such a file can be generated using the 'nm' tool. +BasicSymbolProviderPrefPage_btnBrowse=Browse... +BasicSymbolProviderPrefPage_description=Symbol provider configuration for trace "{0}" +BasicSymbolProviderPrefPage_ImportMappingDialogTitle=Select Mapping File +BasicSymbolProviderPrefPage_ImportBinaryFileDialogTitle=Select Binary File +BasicSymbolProviderPrefPage_errorFileDoesNotExists=The current path is not a file or it does not exist +BasicSymbolProviderPrefPage_errorSpecifyFile=Please specify a valid binary or mapping file +BasicSymbolProviderPrefPage_loadingConfigurations=Loading configurations... + diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProvider.java new file mode 100644 index 0000000000..9d75550ebb --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProvider.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import java.io.File; +import java.util.Collections; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.internal.tmf.core.callstack.FunctionNameMapper; +import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfCallsite; +import org.eclipse.tracecompass.tmf.core.event.lookup.TmfCallsite; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderPreferencePage; + +/** + * The {@link BasicSymbolProvider} can use either an executable or a simple + * symbol mapping file to resolve symbols. + * + * @author Robert Kiss + * + */ +public class BasicSymbolProvider implements ISymbolProvider { + + private final @NonNull ITmfTrace fTrace; + + private @NonNull Map fMapping = Collections.emptyMap(); + + private String fSource; + + private @NonNull SourceKind fKind = SourceKind.BINARY; + + private boolean fConfigured; + + /** + * The kind of source this provider is configured with + * + */ + public static enum SourceKind { + /** + * Literal for binary configuration + */ + BINARY, + + /** + * Literal for mapping configuration + */ + MAPPING; + } + + /** + * Create a new {@link BasicSymbolProvider} for the given trace + * + * @param trace + * A non-null trace + */ + public BasicSymbolProvider(@NonNull ITmfTrace trace) { + fTrace = trace; + } + + /** + * + * @return the configured source + */ + public String getConfiguredSource() { + return fSource; + } + + /** + * @return the configured source kind + */ + public @NonNull SourceKind getConfiguredSourceKind() { + return fKind; + } + + /** + * Set the configuration to the given source and kind. + * + * @param fileSource + * File path to either a binary file or a mapping file. + * @param kind + * the type of the referenced file + */ + public void setConfiguredSource(String fileSource, @NonNull SourceKind kind) { + fSource = fileSource; + fKind = kind; + fConfigured = false; + } + + @Override + public @NonNull ITmfTrace getTrace() { + return fTrace; + } + + @Override + public void loadConfiguration(IProgressMonitor monitor) { + if (!fConfigured) { + synchronized (this) { + if (!fConfigured) { + try { + fMapping = Collections.emptyMap(); + if (fSource != null) { + File file = new File(fSource); + if (file.isFile()) { + Map result; + if (fKind == SourceKind.BINARY) { + result = FunctionNameMapper.mapFromBinaryFile(file); + } else { + result = FunctionNameMapper.mapFromNmTextFile(file); + } + if (result != null) { + fMapping = result; + } + } + } + } finally { + fConfigured = true; + } + } + } + } + } + + @Override + public @Nullable String getSymbolText(long address) { + loadConfiguration(null); + return fMapping.get(Long.toHexString(address)); + } + + @Override + public @Nullable ITmfCallsite getSymbolInfo(long address) { + loadConfiguration(null); + String symbolText = getSymbolText(address); + if (symbolText != null) { + return new TmfCallsite(null, symbolText, -1); + } + return null; + } + + @Override + public ISymbolProviderPreferencePage createPreferencePage() { + return new BasicSymbolProviderPreferencePage(this); + } + +} 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 new file mode 100644 index 0000000000..860d607b02 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderFactory.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderFactory; + +/** + * Basic symbol provider factory that can handle any trace. It will create a + * {@link BasicSymbolProvider}. + * + * @author Robert Kiss + * + */ +@NonNullByDefault +public class BasicSymbolProviderFactory implements ISymbolProviderFactory { + + @Override + public ISymbolProvider createProvider(ITmfTrace trace) { + return new BasicSymbolProvider(trace); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderPreferencePage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderPreferencePage.java new file mode 100644 index 0000000000..029c04b253 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderPreferencePage.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import java.io.File; +import java.text.MessageFormat; + +import org.eclipse.jdt.annotation.NonNull; +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.FileDialog; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tracecompass.internal.tmf.ui.Messages; +import org.eclipse.tracecompass.internal.tmf.ui.symbols.BasicSymbolProvider.SourceKind; +import org.eclipse.tracecompass.tmf.ui.symbols.AbstractSymbolProviderPreferencePage; + +/** + * Preference page that allows the user to configure a + * {@link BasicSymbolProvider} + * + * @author Robert Kiss + * + */ +public class BasicSymbolProviderPreferencePage extends AbstractSymbolProviderPreferencePage { + + private Button fRadioBinaryFile; + private Text fTextBinaryFile; + private Button fButtonBrowseBinary; + private Button fRadioMappingFile; + private Text fTextMappingFile; + private Button fButtonBrowseMapping; + + /** + * Creates a new object for the given provider + * + * @param provider + * a non-null provider + */ + public BasicSymbolProviderPreferencePage(@NonNull BasicSymbolProvider provider) { + super(provider); + setDescription(MessageFormat.format(Messages.BasicSymbolProviderPrefPage_description, provider.getTrace().getName())); + setValid(true); + } + + @Override + protected Control createContents(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + composite.setLayout(new GridLayout(3, false)); + + fRadioBinaryFile = new Button(composite, SWT.RADIO); + fRadioBinaryFile.setText(Messages.BasicSymbolProviderPrefPage_radioBinaryFile_text); + fRadioBinaryFile.setToolTipText(Messages.BasicSymbolProviderPrefPage_radioBinaryFile_tooltip); + fRadioBinaryFile.setSelection(true); + fRadioBinaryFile.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + switchToSourceKind(SourceKind.BINARY, true); + } + }); + + fTextBinaryFile = new Text(composite, SWT.BORDER); + fTextBinaryFile.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + fTextBinaryFile.setEditable(false); + + fButtonBrowseBinary = new Button(composite, SWT.NONE); + fButtonBrowseBinary.setText(Messages.BasicSymbolProviderPrefPage_btnBrowse); + fButtonBrowseBinary.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + browseForFile(fTextBinaryFile, Messages.BasicSymbolProviderPrefPage_ImportBinaryFileDialogTitle); + } + }); + + fRadioMappingFile = new Button(composite, SWT.RADIO); + fRadioMappingFile.setText(Messages.BasicSymbolProviderPrefPage_radioMappingFile_text); + fRadioMappingFile.setToolTipText(Messages.BasicSymbolProviderPrefPage_radioMappingFile_tooltip); + fRadioMappingFile.setSelection(false); + fRadioMappingFile.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + switchToSourceKind(SourceKind.MAPPING, true); + } + }); + + fTextMappingFile = new Text(composite, SWT.BORDER); + fTextMappingFile.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + fTextMappingFile.setEnabled(false); + fTextMappingFile.setEditable(false); + + fButtonBrowseMapping = new Button(composite, SWT.NONE); + fButtonBrowseMapping.setText(Messages.BasicSymbolProviderPrefPage_btnBrowse); + fButtonBrowseMapping.setEnabled(false); + fButtonBrowseMapping.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + browseForFile(fTextMappingFile, Messages.BasicSymbolProviderPrefPage_ImportMappingDialogTitle); + } + }); + + loadProviderSettings(); + + return composite; + } + + private void browseForFile(Text fileField, String dialogTitle) { + FileDialog fileDialog = new FileDialog(getShell(), SWT.OPEN); + fileDialog.setText(dialogTitle); + String filePath = fileDialog.open(); + if (filePath != null) { + fileField.setText(filePath); + broadcastChanges(); + } + + } + + private void loadProviderSettings() { + BasicSymbolProvider provider = (BasicSymbolProvider) getSymbolProvider(); + String source = provider.getConfiguredSource(); + SourceKind sourceKind = provider.getConfiguredSourceKind(); + if (source != null) { + if (sourceKind == SourceKind.BINARY) { + fTextBinaryFile.setText(source); + } else { + fTextMappingFile.setText(source); + } + } + + switchToSourceKind(sourceKind, false); + broadcastChanges(); + } + + private void switchToSourceKind(@NonNull SourceKind kind, boolean broadcastChanges) { + fRadioBinaryFile.setSelection(kind == SourceKind.BINARY); + fTextBinaryFile.setEnabled(kind == SourceKind.BINARY); + fButtonBrowseBinary.setEnabled(kind == SourceKind.BINARY); + + fRadioMappingFile.setSelection(kind == SourceKind.MAPPING); + fTextMappingFile.setEnabled(kind == SourceKind.MAPPING); + fButtonBrowseMapping.setEnabled(kind == SourceKind.MAPPING); + if (broadcastChanges) { + broadcastChanges(); + } + } + + @Override + public void saveConfiguration() { + BasicSymbolProvider provider = (BasicSymbolProvider) getSymbolProvider(); + provider.setConfiguredSource(getCurrentSource(), getCurrentSourceKind()); + } + + private @NonNull SourceKind getCurrentSourceKind() { + if (fRadioBinaryFile.getSelection()) { + return SourceKind.BINARY; + } + return SourceKind.MAPPING; + } + + private String getCurrentSource() { + if (fRadioBinaryFile.getSelection()) { + return fTextBinaryFile.getText(); + } + return fTextMappingFile.getText(); + } + + private void broadcastChanges() { + String filePath = getCurrentSource(); + String errorMessage = null; + if (filePath != null && filePath.length() > 0) { + File file = new File(filePath); + if (!file.isFile()) { + errorMessage = Messages.BasicSymbolProviderPrefPage_errorFileDoesNotExists; + } + } else { + errorMessage = Messages.BasicSymbolProviderPrefPage_errorSpecifyFile; + } + setErrorMessage(errorMessage); + setValid(errorMessage == null); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/AbstractSymbolProviderPreferencePage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/AbstractSymbolProviderPreferencePage.java new file mode 100644 index 0000000000..1c9544cd00 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/AbstractSymbolProviderPreferencePage.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jface.preference.PreferencePage; + +/** + * Abstract implementation of the {@link ISymbolProviderPreferencePage}. Instead + * of implementing the interface one should extend this class. + * + * @author Robert Kiss + * @since 2.0 + */ +@NonNullByDefault +public abstract class AbstractSymbolProviderPreferencePage extends PreferencePage implements ISymbolProviderPreferencePage { + + private final ISymbolProvider fProvider; + + /** + * Create a new instance that knows how to configure the given provider + * + * @param provider + * the {@link ISymbolProvider} to configure + */ + public AbstractSymbolProviderPreferencePage(ISymbolProvider provider) { + fProvider = provider; + setTitle(provider.getTrace().getName()); + noDefaultAndApplyButton(); + } + + @Override + public ISymbolProvider getSymbolProvider() { + return fProvider; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/DefaultSymbolProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/DefaultSymbolProvider.java new file mode 100644 index 0000000000..aa25c11953 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/DefaultSymbolProvider.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfCallsite; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +/** + * A default implementation of the {@link ISymbolProvider} which return a hex + * format representation of the symbol address + * + * @author Robert Kiss + * @since 2.0 + * + */ +@NonNullByDefault +public class DefaultSymbolProvider implements ISymbolProvider { + + private final ITmfTrace fTrace; + + /** + * Create a new provider for the given trace + * + * @param trace + * the trace + */ + public DefaultSymbolProvider(ITmfTrace trace) { + fTrace = trace; + } + + @Override + public void loadConfiguration(@Nullable IProgressMonitor monitor) { + // no configuration here + } + + @Override + public ITmfTrace getTrace() { + return fTrace; + } + + /** + * Return a hex formated representation of the given address + * + * @param address + * the symbol address + * @return the hex representation of the given address + */ + @Override + public @NonNull String getSymbolText(long address) { + if ((address & (0xFFFFFFFF << 32)) == 0) { + return String.format("%08x", address); //$NON-NLS-1$ + } + return String.format("%016x", address); //$NON-NLS-1$ + } + + /** + * The default symbol provider will return null for this method + * + * @param address + * the symbol address + * @return always null + */ + @Override + public @Nullable ITmfCallsite getSymbolInfo(long address) { + return null; + } + + /** + * @return null because the default symbol provider doesn't support + * configuration + */ + @Override + public @Nullable ISymbolProviderPreferencePage createPreferencePage() { + return null; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProvider.java new file mode 100644 index 0000000000..cd19ef4daf --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProvider.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfCallsite; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTrace; + +/** + * An ISymbolProvider is used to map symbol addresses that might be found inside + * an {@link TmfTrace} into human readable strings. + * + * @author Robert Kiss + * @since 2.0 + * @see ISymbolProviderFactory + * + */ +public interface ISymbolProvider { + + /** + * @return the trace that this class resolves symbols for + */ + @NonNull ITmfTrace getTrace(); + + /** + * Some providers might have configurations that take some time to load. All + * the CPU intensive load operations shall be done in this method. The + * adopters shall call this method at an opportune moment when cancellation + * and UI feedback is possible. However, the implementors of this interface + * shall not assume that this method has been called. + * + * @param monitor + * The progress monitor to use, can be null + */ + void loadConfiguration(IProgressMonitor monitor); + + /** + * Return the symbol text corresponding to the given address or null if + * there is no such symbol + * + * @param address + * the address of the symbol + * @return the symbol text or null if the symbol cannot be found + */ + @Nullable String getSymbolText(long address); + + /** + * Return additional information regarding the symbol from the given address + * or null if the symbol cannot be found + * + * @param address + * the address of the symbol + * @return the symbol {@link ITmfCallsite} information or null if the symbol + * cannot be found + */ + @Nullable ITmfCallsite getSymbolInfo(long address); + + /** + * Create the {@link ISymbolProviderPreferencePage} that can be used to + * configure this {@link ISymbolProvider} + * + * @return the {@link ISymbolProviderPreferencePage} or null if this symbol + * provider does not offer a configuration UI + */ + @Nullable ISymbolProviderPreferencePage createPreferencePage(); + +} 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 new file mode 100644 index 0000000000..217c4cd0b2 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderFactory.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +/** + * Instance of this interface can be contributed using the + * org.eclipse.tracecompass.tmf.ui.symbolProvider extension and is + * used to create instances of {@link ISymbolProvider} + * + * @author Robert Kiss + * + * @since 2.0 + */ +public interface ISymbolProviderFactory { + + /** + * Create a provider for the given trace. If this factory does not know how + * to handle the given trace it will return null; + * + * @param trace + * A non-null trace + * @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); + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderPreferencePage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderPreferencePage.java new file mode 100644 index 0000000000..8b8042936e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderPreferencePage.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jface.preference.IPreferencePage; + +/** + * Allow the user to configure a {@link ISymbolProvider} + * + * @author Robert Kiss + * @since 2.0 + * + */ +@NonNullByDefault +public interface ISymbolProviderPreferencePage extends IPreferencePage { + + /** + * Return the {@link ISymbolProvider} associated with this preference page + * + * @return the associated {@link ISymbolProvider} + */ + ISymbolProvider getSymbolProvider(); + + /** + * Save the configuration that is currently in UI into the corresponding + * {@link ISymbolProvider}. + */ + void saveConfiguration(); + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderConfigDialog.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderConfigDialog.java new file mode 100644 index 0000000000..1a6b4af7b0 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderConfigDialog.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.preference.IPreferencePageContainer; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +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.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.internal.tmf.ui.Messages; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +/** + * This class shall be used to configure one or more {@link ISymbolProvider}. It + * receives an array of {@link ISymbolProviderPreferencePage} and creates a + * dialog that can be used to configure the corresponding providers. If the + * {@link #open()} method exits with {@link IDialogConstants#OK_ID} the caller + * shall assume that the corresponding {@link ISymbolProvider}'s have a new + * configuration. + * + * + * @author Robert Kiss + * @since 2.0 + * + */ +public class SymbolProviderConfigDialog extends TitleAreaDialog implements IPreferencePageContainer { + + private ISymbolProviderPreferencePage[] fPreferencePages; + private CTabItem[] fPageTabs; + private CTabFolder fTabFolder; + + private IRunnableWithProgress configJob = (monitor) -> { + // saving the configuration is fast and need UI access + SymbolProviderConfigDialog.this.getContents().getDisplay().syncExec(() -> { + for (int i = 0; i < fPreferencePages.length; i++) { + ISymbolProviderPreferencePage page = fPreferencePages[i]; + page.saveConfiguration(); + } + }); + monitor.beginTask(Messages.BasicSymbolProviderPrefPage_loadingConfigurations, fPreferencePages.length * 100); + try { + for (int i = 0; i < fPreferencePages.length; i++) { + ISymbolProviderPreferencePage page = fPreferencePages[i]; + page.getSymbolProvider().loadConfiguration(monitor); + monitor.worked(100); + } + } finally { + monitor.done(); + } + }; + + /** + * Create a new dialog that will use the given shall and preference pages. + * + * @param parentShell + * The parent shell + * @param pages + * the pages that provides the configuration UI for + * {@link ISymbolProvider}'s. The array shall not be empty and + * shall not contain null elements. + * + */ + public SymbolProviderConfigDialog(Shell parentShell, ISymbolProviderPreferencePage... pages) { + super(parentShell); + fPreferencePages = pages; + } + + @Override + protected Control createDialogArea(Composite parent) { + getShell().setText(Messages.SymbolProviderConfigDialog_title); + setTitle(Messages.SymbolProviderConfigDialog_title); + setMessage(Messages.SymbolProviderConfigDialog_message); + + Composite composite = (Composite) super.createDialogArea(parent); + composite.setLayout(new GridLayout()); + + // if we have one single provider that we don't need a tab + if (fPreferencePages.length == 1) { + attachPreference(composite, fPreferencePages[0]); + updateMessage(0); + } else { + fTabFolder = new CTabFolder(composite, SWT.NONE); + fTabFolder.setLayoutData(new GridData(GridData.FILL_BOTH)); + fPageTabs = new CTabItem[fPreferencePages.length]; + for (int i = 0; i < fPreferencePages.length; i++) { + ISymbolProviderPreferencePage page = fPreferencePages[i]; + fPageTabs[i] = new CTabItem(fTabFolder, SWT.NONE); + fPageTabs[i].setText(page.getTitle()); + Composite child = new Composite(fTabFolder, SWT.NONE); + child.setLayout(new GridLayout()); + child.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true)); + fPageTabs[i].setControl(child); + attachPreference(child, page); + updateMessage(i); + } + fTabFolder.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateMessage(fTabFolder.indexOf((CTabItem) e.item)); + } + }); + } + return composite; + } + + @Override + public boolean isHelpAvailable() { + return false; + } + + private void attachPreference(Composite composite, ISymbolProviderPreferencePage page) { + page.setContainer(this); + page.createControl(composite); + page.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); + } + + @Override + public IPreferenceStore getPreferenceStore() { + // not used + return null; + } + + @Override + public void updateTitle() { + // not used + } + + @Override + public void updateButtons() { + // nothing to do + } + + @Override + protected void okPressed() { + boolean cancel = false; + try { + new ProgressMonitorDialog(getShell()).run(true, false, configJob); + } catch (InvocationTargetException e) { + setMessage(e.getMessage(), IMessageProvider.ERROR); + cancel = true; + } catch (InterruptedException e) { + // ignore + } + if (!cancel) { + super.okPressed(); + } + } + + @Override + public void updateMessage() { + if (fTabFolder == null) { + updateMessage(0); + } else { + updateMessage(fTabFolder.getSelectionIndex()); + } + } + + private void updateMessage(int pageIndex) { + ISymbolProviderPreferencePage currentPage = fPreferencePages[pageIndex]; + String message = currentPage.getMessage(); + String errorMessage = currentPage.getErrorMessage(); + int messageType = IMessageProvider.NONE; + + if (errorMessage != null) { + message = errorMessage; + messageType = IMessageProvider.ERROR; + } + setMessage(message, messageType); + + if (fPreferencePages.length > 1) { + // update the corresponding tab icon + if (messageType == IMessageProvider.ERROR) { + fPageTabs[pageIndex].setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK)); + } else { + fPageTabs[pageIndex].setImage(null); + } + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderManager.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderManager.java new file mode 100644 index 0000000000..01f67cafb8 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderManager.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2016 Movidius 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.tmf.ui.symbols; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +/** + * This class offer services around the + * org.eclipse.tracecompass.tmf.ui.symbolProvider extension point. + * + * @author Robert Kiss + * @since 2.0 + * + */ +public final class SymbolProviderManager { + + /** + * The singleton instance of this manager + */ + private static SymbolProviderManager INSTANCE; + + private static final String EXTENSION_POINT_ID = "org.eclipse.tracecompass.tmf.ui.symbolProvider"; //$NON-NLS-1$ + private static final String ELEM_NAME_PROVIDER = "providerFactory"; //$NON-NLS-1$ + private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + private static final String ATTR_PRIORITY = "priority"; //$NON-NLS-1$ + + private final List fProviders; + + private final Map> fInstances = new WeakHashMap<>(); + + /** + * Internal class used to store extension point information + * + */ + private static class SymbolProviderFactoryWrapper { + + public final ISymbolProviderFactory factory; + public final int priority; + + private SymbolProviderFactoryWrapper(ISymbolProviderFactory factory, int priority) { + this.factory = factory; + this.priority = priority; + + } + + } + + /** + * + * @return the singleton instance of this class + */ + @SuppressWarnings("null") + public static synchronized @NonNull SymbolProviderManager getInstance() { + if (INSTANCE == null) { + INSTANCE = new SymbolProviderManager(); + } + return INSTANCE; + } + + /** + * The private constructor of this manager + */ + private SymbolProviderManager() { + fProviders = new ArrayList<>(); + IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID); + for (IConfigurationElement element : configElements) { + if (ELEM_NAME_PROVIDER.equals(element.getName())) { + try { + Object extension = element.createExecutableExtension(ATTR_CLASS); + int priority = 0; + try { + priority = Integer.parseInt(element.getAttribute(ATTR_PRIORITY)); + } catch (NumberFormatException e) { + // safe to ignore + } + fProviders.add(new SymbolProviderFactoryWrapper((ISymbolProviderFactory) extension, priority)); + } catch (CoreException | ClassCastException e) { + Activator.getDefault().logError("Exception while loading extensions", e); //$NON-NLS-1$ + } + } + } + // Those with a higher priority need to be on top + fProviders.sort(Comparator.comparingLong(o -> -o.priority)); + } + + /** + * Locate an {@link ISymbolProvider} capable to resolve symbols from the + * given trace. If no such provider is defined an instance of + * {@link DefaultSymbolProvider} will be returned + * + * @param trace + * The trace to create a provider for + * @return a valid {@link ISymbolProvider}, never null + */ + public @NonNull ISymbolProvider getSymbolProvider(@NonNull ITmfTrace trace) { + // Check to see if we already have a provider for this trace + synchronized (fInstances) { + WeakReference reference = fInstances.get(trace); + if (reference != null) { + ISymbolProvider provider = reference.get(); + if (provider != null) { + return provider; + } + } + // we don't have yet an instance, build one + for (SymbolProviderFactoryWrapper wrapper : fProviders) { + ISymbolProviderFactory factory = wrapper.factory; + ISymbolProvider provider = factory.createProvider(trace); + if (provider != null) { + fInstances.put(trace, new WeakReference<>(provider)); + return provider; + } + } + } + // No provider found, return the default one + return new DefaultSymbolProvider(trace); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java index 991e625fa8..4b7f68ab2c 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java @@ -112,8 +112,7 @@ public class CallStackPresentationProvider extends TimeGraphPresentationProvider try { ITmfStateValue value = ss.querySingleState(event.getTime(), entry.getQuark()).getStateValue(); if (!value.isNull()) { - String address = value.toString(); - return fView.getFunctionName(address); + return fView.getFunctionName(entry.getTrace(), value); } } catch (AttributeNotFoundException e) { Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$ @@ -143,8 +142,7 @@ public class CallStackPresentationProvider extends TimeGraphPresentationProvider try { ITmfStateValue value = ss.querySingleState(event.getTime(), entry.getQuark()).getStateValue(); if (!value.isNull()) { - String address = value.toString(); - String name = fView.getFunctionName(address); + String name = fView.getFunctionName(entry.getTrace(), value); gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE)); Utils.drawText(gc, name, bounds.x, bounds.y, bounds.width, bounds.height, true, true); } diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java index cbf738f593..110b9a3bc3 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java @@ -14,7 +14,6 @@ package org.eclipse.tracecompass.tmf.ui.views.callstack; -import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -24,9 +23,6 @@ import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.action.Action; @@ -35,6 +31,7 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.IPropertyChangeListener; @@ -50,10 +47,8 @@ import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Tree; -import org.eclipse.tracecompass.internal.tmf.core.callstack.FunctionNameMapper; import org.eclipse.tracecompass.internal.tmf.ui.Activator; import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants; import org.eclipse.tracecompass.internal.tmf.ui.Messages; @@ -68,6 +63,7 @@ import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type; import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal; import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; @@ -78,6 +74,10 @@ import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampDelta; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderPreferencePage; +import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderConfigDialog; +import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderManager; import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractTimeGraphView; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider; @@ -128,7 +128,6 @@ public class CallStackView extends AbstractTimeGraphView { private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$ private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$ - private static final String IMPORT_MAPPING_ICON_PATH = "icons/etool16/import.gif"; //$NON-NLS-1$ private static final String IMPORT_BINARY_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$ private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$ @@ -153,8 +152,7 @@ public class CallStackView extends AbstractTimeGraphView { // Fields // ------------------------------------------------------------------------ - /** The map to map function addresses to function names */ - private Map fNameMapping; + private final Map fSymbolProviders = new HashMap<>(); // The next event action private Action fNextEventAction; @@ -168,11 +166,8 @@ public class CallStackView extends AbstractTimeGraphView { // The previous item action private Action fPreviousItemAction; - // The action to import a function-name mapping file - private Action fImportMappingAction; - // The action to import a binary file mapping */ - private Action fImportBinaryFileMappingAction; + private Action fConfigureSymbolsAction; // The saved time sync. signal used when switching off the pinning of a view private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal; @@ -504,6 +499,26 @@ public class CallStackView extends AbstractTimeGraphView { // Internal // ------------------------------------------------------------------------ + @Override + @TmfSignalHandler + public void traceClosed(TmfTraceClosedSignal signal) { + super.traceClosed(signal); + synchronized(fSymbolProviders){ + for(ITmfTrace trace : getTracesToBuild(signal.getTrace())){ + fSymbolProviders.remove(trace); + } + } + } + + /** + * @since 2.0 + */ + @Override + protected void refresh() { + super.refresh(); + updateConfigureSymbolsAction(); + } + @Override protected void buildEventList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) { if (monitor.isCanceled()) { @@ -539,6 +554,16 @@ public class CallStackView extends AbstractTimeGraphView { if (start == end && !complete) { // when complete execute one last time regardless of end time continue; } + + ISymbolProvider provider = fSymbolProviders.get(trace); + if (provider == null) { + provider = SymbolProviderManager.getInstance().getSymbolProvider(trace); + provider.loadConfiguration(monitor); + fSymbolProviders.put(trace, provider); + } + + getConfigureSymbolsAction().setEnabled(true); + List threadQuarks = ss.getQuarks(threadPaths); TraceEntry traceEntry = traceEntryMap.get(trace); if (traceEntry == null) { @@ -717,21 +742,11 @@ public class CallStackView extends AbstractTimeGraphView { } for (ITimeGraphEntry child : threadEntry.getChildren()) { CallStackEntry callStackEntry = (CallStackEntry) child; + ITmfTrace trace = callStackEntry.getTrace(); try { ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark()); ITmfStateValue nameValue = stackLevelInterval.getStateValue(); - String name = ""; //$NON-NLS-1$ - try { - if (nameValue.getType() == Type.STRING) { - String address = nameValue.unboxStr(); - name = getFunctionName(address); - } else if (nameValue.getType() == Type.INTEGER) { - name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$ - } else if (nameValue.getType() == Type.LONG) { - name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$ - } - } catch (StateValueTypeException e) { - } + String name = getFunctionName(trace, nameValue); callStackEntry.setFunctionName(name); if (name.length() > 0) { callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime()); @@ -750,6 +765,38 @@ public class CallStackView extends AbstractTimeGraphView { } } + String getFunctionName(ITmfTrace trace, ITmfStateValue nameValue) { + long address = Long.MAX_VALUE; + String name = ""; //$NON-NLS-1$ + try { + if (nameValue.getType() == Type.STRING) { + name = nameValue.unboxStr(); + try { + address = Long.parseLong(name, 16); + } catch (NumberFormatException e) { + // ignore + } + } else if (nameValue.getType() == Type.INTEGER) { + name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$ + address = nameValue.unboxInt(); + } else if (nameValue.getType() == Type.LONG) { + name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$ + address = nameValue.unboxLong(); + } + } catch (StateValueTypeException e) { + } + if (address != Long.MAX_VALUE) { + ISymbolProvider provider = fSymbolProviders.get(trace); + if (provider != null) { + String symbol = provider.getSymbolText(address); + if (symbol != null) { + name = symbol; + } + } + } + return name; + } + private void makeActions() { fPreviousItemAction = getTimeGraphViewer().getPreviousItemAction(); fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText); @@ -786,8 +833,7 @@ public class CallStackView extends AbstractTimeGraphView { @Override protected void fillLocalToolBar(IToolBarManager manager) { makeActions(); - manager.add(getImportBinaryAction()); - manager.add(getImportMappingAction()); + manager.add(getConfigureSymbolsAction()); manager.add(new Separator()); manager.add(getSortByNameAction()); manager.add(getSortByIdAction()); @@ -946,72 +992,6 @@ public class CallStackView extends AbstractTimeGraphView { // Methods related to function name mapping // ------------------------------------------------------------------------ - /** - * Common code for all import file mapping actions - */ - private abstract class AbstractImportFileMappingAction extends Action { - private final String fDialogTitle; - - private AbstractImportFileMappingAction(String dialogTitle) { - fDialogTitle = dialogTitle; - } - - @Override - public void run() { - FileDialog dialog = new FileDialog(getViewSite().getShell()); - dialog.setText(fDialogTitle); - final String filePath = dialog.open(); - if (filePath == null) { - /* No file was selected, don't change anything */ - return; - } - - /* - * Start the mapping import in a separate thread (we do not want to - * UI thread to do this). - */ - Job job = new Job(Messages.CallStackView_ImportMappingJobName) { - @Override - public IStatus run(IProgressMonitor monitor) { - fNameMapping = doMapping(new File(filePath)); - - /* Refresh call stack entries and event labels */ - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - synchingToTime(getTimeGraphViewer().getSelectionBegin()); - } - }); - return Status.OK_STATUS; - } - }; - job.schedule(); - } - - abstract Map doMapping(File file); - } - - /** - * Toolbar icon to import the function address-to-name mapping file. - */ - private Action getImportMappingAction() { - if (fImportMappingAction != null) { - return fImportMappingAction; - } - fImportMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportMappingDialogTitle) { - @Override - Map doMapping(File file) { - return FunctionNameMapper.mapFromNmTextFile(file); - } - }; - - fImportMappingAction.setText(Messages.CallStackView_ImportMappingButtonText); - fImportMappingAction.setToolTipText(Messages.CallStackView_ImportMappingButtonTooltip); - fImportMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH)); - - return fImportMappingAction; - } - private Action getSortByNameAction() { if (fSortByNameAction == null) { fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) { @@ -1133,42 +1113,55 @@ public class CallStackView extends AbstractTimeGraphView { refresh(); } - /** - * Toolbar icon to import the function address-to-name mapping binary file. - */ - private Action getImportBinaryAction() { - if (fImportBinaryFileMappingAction != null) { - return fImportBinaryFileMappingAction; + private Action getConfigureSymbolsAction() { + if (fConfigureSymbolsAction != null) { + return fConfigureSymbolsAction; } - fImportBinaryFileMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportBinaryFileDialogTitle) { + fConfigureSymbolsAction = new Action(Messages.CallStackView_ConfigureSymbolProvidersText) { @Override - Map doMapping(File file) { - return FunctionNameMapper.mapFromBinaryFile(file); + public void run() { + SymbolProviderConfigDialog dialog = new SymbolProviderConfigDialog(getSite().getShell(), getProviderPages()); + if (dialog.open() == IDialogConstants.OK_ID) { + refresh(); + } } }; - fImportBinaryFileMappingAction.setText(Messages.CallStackView_ImportBinaryFileButtonText); - fImportBinaryFileMappingAction.setToolTipText(Messages.CallStackView_ImportBinaryFileButtonTooltip); - fImportBinaryFileMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH)); + fConfigureSymbolsAction.setToolTipText(Messages.CallStackView_ConfigureSymbolProvidersTooltip); + fConfigureSymbolsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH)); + fConfigureSymbolsAction.setEnabled(false); - return fImportBinaryFileMappingAction; + return fConfigureSymbolsAction; } - String getFunctionName(String address) { - if (fNameMapping == null) { - /* No mapping available, just print the addresses */ - return address; - } - String ret = fNameMapping.get(address); - if (ret == null) { - /* - * We didn't find this address in the mapping file, just use the - * address - */ - return address; + /** + * @return an array of {@link ISymbolProviderPreferencePage} that will + * configure the current traces + */ + private ISymbolProviderPreferencePage[] getProviderPages() { + List pages = new ArrayList<>(); + ITmfTrace trace = getTrace(); + if (trace != null) { + for (ITmfTrace subTrace : getTracesToBuild(trace)) { + ISymbolProvider provider = fSymbolProviders.get(subTrace); + if (provider != null) { + ISymbolProviderPreferencePage page = provider.createPreferencePage(); + if (page != null) { + pages.add(page); + } + } + } } - return ret; + return pages.toArray(new ISymbolProviderPreferencePage[pages.size()]); + } + + /** + * Update the enable status of the configure symbols action + */ + private void updateConfigureSymbolsAction() { + ISymbolProviderPreferencePage[] providerPages = getProviderPages(); + getConfigureSymbolsAction().setEnabled(providerPages.length > 0); } } -- 2.34.1