tmf: Use a symbol provider to locate symbols
authorRobert Kiss <robert.kiss@gmail.com>
Fri, 26 Feb 2016 16:57:58 +0000 (18:57 +0200)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Fri, 11 Mar 2016 23:29:08 +0000 (18:29 -0500)
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 <robert.kiss@gmail.com>
Reviewed-on: https://git.eclipse.org/r/67442
Reviewed-by: Hudson CI
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-by: Alexandre Montplaisir <alexmonthy@efficios.com>
Tested-by: Alexandre Montplaisir <alexmonthy@efficios.com>
18 files changed:
lttng/org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests/src/org/eclipse/tracecompass/lttng2/ust/ui/swtbot/tests/CallStackViewTest.java
tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties
tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml
tmf/org.eclipse.tracecompass.tmf.ui/schema/org.eclipse.tracecompass.tmf.ui.symbolProvider.exsd [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Messages.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/messages.properties
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProvider.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderFactory.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/symbols/BasicSymbolProviderPreferencePage.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/AbstractSymbolProviderPreferencePage.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/DefaultSymbolProvider.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProvider.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderFactory.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/ISymbolProviderPreferencePage.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderConfigDialog.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/symbols/SymbolProviderManager.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java

index a85851ef22b3edef01d97e148d5f1f51b6547f1f..0e517f813217b7293eeb13f65410e944b4a03f30 100644 (file)
@@ -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<String> 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,
             "",
index dc3acfa4598d6c3e62bb8a05d014b5753545df59..15d90bba7a76acfa0c11cb7097ce526cd45cc497 100644 (file)
@@ -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
index 530a99bb73facca02fb7e7c7adf02cafb897fb7b..fe60b8acbad858973883fb9a513e5a10bc2fa909 100644 (file)
@@ -3,6 +3,7 @@
 <plugin>
    <extension-point id="org.eclipse.linuxtools.tmf.ui.uml2SDLoader" name="%extensionpoint.sequence_diagram_loader.name" schema="schema/org.eclipse.linuxtools.tmf.ui.uml2SDLoader.exsd"/>
    <extension-point id="org.eclipse.linuxtools.tmf.ui.tracetypeui" name="%extensionpoint.trace_type_ui.name" schema="schema/org.eclipse.linuxtools.tmf.ui.tracetypeui.exsd"/>
+   <extension-point id="org.eclipse.tracecompass.tmf.ui.symbolProvider" name="%extensionpoint.symbol_provider.name" schema="schema/org.eclipse.tracecompass.tmf.ui.symbolProvider.exsd"/>
 
     <extension
          point="org.eclipse.ui.perspectives">
          </description>
       </colorDefinition>
    </extension>
+   <extension
+         point="org.eclipse.tracecompass.tmf.ui.symbolProvider">
+      <providerFactory
+            class="org.eclipse.tracecompass.internal.tmf.ui.symbols.BasicSymbolProviderFactory"
+            id="org.eclipse.tracecompass.tmf.ui.providerFactory1"
+            priority="0">
+      </providerFactory>
+   </extension>
 </plugin>
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 (file)
index 0000000..f435ebd
--- /dev/null
@@ -0,0 +1,132 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.tracecompass.tmf.ui" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.tracecompass.tmf.ui" id="symbolProvider" name="TMF Symbol provider extension"/>
+      </appinfo>
+      <documentation>
+         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.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="providerFactory" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="providerFactory">
+      <annotation>
+         <documentation>
+            A symbol provider factory can be used to translate symbol addresses that can be found inside traces into symbol names.
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The ID of the extension
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The name of the class responsible to create an ISymbolProvider
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderFactory"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="priority" type="string" use="default" value="50">
+            <annotation>
+               <documentation>
+                  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.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         2.0
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         Since 2.0
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         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 &lt;a 
+href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+</schema>
index b860be437bdd1e91804f848ffee6de79773b60cd..5ca1d440a5abe819406fc7a526b6aa1862337404 100644 (file)
@@ -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);
index 0e5e0c985162c9d9dfaa351564aaf606e3ec154f..4dbccf37a857b89db3abfce3806d4a9a0df227da 100644 (file)
@@ -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 (file)
index 0000000..9d75550
--- /dev/null
@@ -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<String, String> 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<String, String> 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 (file)
index 0000000..860d607
--- /dev/null
@@ -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 (file)
index 0000000..029c04b
--- /dev/null
@@ -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 (file)
index 0000000..1c9544c
--- /dev/null
@@ -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 (file)
index 0000000..aa25c11
--- /dev/null
@@ -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 (file)
index 0000000..cd19ef4
--- /dev/null
@@ -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 (file)
index 0000000..217c4cd
--- /dev/null
@@ -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
+ * <code>org.eclipse.tracecompass.tmf.ui.symbolProvider</code> 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 (file)
index 0000000..8b80429
--- /dev/null
@@ -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 (file)
index 0000000..1a6b4af
--- /dev/null
@@ -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 (file)
index 0000000..01f67ca
--- /dev/null
@@ -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
+ * <code>org.eclipse.tracecompass.tmf.ui.symbolProvider</code> 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<SymbolProviderFactoryWrapper> fProviders;
+
+    private final Map<ITmfTrace, WeakReference<ISymbolProvider>> 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<ISymbolProvider> 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);
+    }
+
+}
index 991e625fa8343fe7b601e4c46713e63fc8705d11..4b7f68ab2c75a791fe928d0277aa50de23390069 100644 (file)
@@ -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);
             }
index cbf738f5931b23d0933224c33a41871b2ad2ae03..110b9a3bc38cf55c4434fb9fb92d88fe67b7c242 100644 (file)
@@ -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<String, String> fNameMapping;
+    private final Map<ITmfTrace, ISymbolProvider> 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<Integer> 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<String, String> 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<String, String> 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<String, String> 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<ISymbolProviderPreferencePage> 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);
     }
 
 }
This page took 0.043978 seconds and 5 git commands to generate.