lttng: Add a Binary Callsite aspect to the debug-info analysis
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Tue, 24 Nov 2015 23:51:24 +0000 (18:51 -0500)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Wed, 25 Nov 2015 22:17:10 +0000 (17:17 -0500)
If the binary is not available at analysis time, we can still display
the binary file and offset information, which comes from the trace.

This information is also re-used by the source callsite.

Change-Id: I40993abedf7057fe6b27cb5c9e787f23e2331f13
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
Reviewed-on: https://git.eclipse.org/r/60843
Reviewed-by: Hudson CI
Reviewed-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Tested-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/BinaryCallsite.java [new file with mode: 0644]
lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/Messages.java
lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoBinaryAspect.java [new file with mode: 0644]
lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoSourceAspect.java
lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/messages.properties
lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/trace/LttngUstTrace.java

diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/BinaryCallsite.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/BinaryCallsite.java
new file mode 100644 (file)
index 0000000..26791f3
--- /dev/null
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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.lttng2.ust.core.analysis.debuginfo;
+
+/**
+ * Object carrying the information about the "binary callsite" corresponding to
+ * an instruction pointer. This consists in:
+ *
+ * <ul>
+ * <li>Binary file</li>
+ * <li>Symbol name</li>
+ * <li>Offset (within the binary)</li>
+ * </ul>
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public class BinaryCallsite {
+
+    private final String fBinaryFilePath;
+    private final String fSymbolName;
+    private final long fOffset;
+
+    /**
+     * Constructor
+     *
+     * @param binaryFilePath
+     *            The path to the binary file on disk, as specified in the trace
+     *            (may or may not be present on the system opening the trace).
+     * @param symbolName
+     *            The name of the symbol in the path. Should not be null, but
+     *            can be an empty string if not available.
+     * @param offset
+     *            The offset *within the binary* of the call site. This should
+     *            be ready to be passed as-is to tools like addr2line.
+     */
+    public BinaryCallsite(String binaryFilePath, String symbolName, long offset) {
+        if (offset < 0) {
+            throw new IllegalArgumentException("Address offset cannot be negative"); //$NON-NLS-1$
+        }
+
+        fBinaryFilePath = binaryFilePath;
+        fSymbolName = symbolName;
+        fOffset = offset;
+    }
+
+    /**
+     * Get the binary file's path
+     *
+     * @return The binary file path
+     */
+    public String getBinaryFilePath() {
+        return fBinaryFilePath;
+    }
+
+    /**
+     * Get the name of the symbol this instruction pointer is from, if it is
+     * available.
+     *
+     * @return The symbol name, or an empty string if not available
+     */
+    public String getSymbolName() {
+        return fSymbolName;
+    }
+
+    /**
+     * Get the address offset within the binary file corresponding to the
+     * instruction pointer.
+     *
+     * @return The address offset
+     */
+    public long getOffset() {
+        return fOffset;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(fBinaryFilePath);
+        if (!fSymbolName.equals("")) { //$NON-NLS-1$
+            sb.append(", "); //$NON-NLS-1$
+            sb.append(Messages.UstDebugInfoAnalysis_Symbol);
+            sb.append('=');
+            sb.append(fSymbolName);
+        }
+        sb.append(", "); //$NON-NLS-1$
+        sb.append(Messages.UstDebugInfoAnalysis_Offset);
+        sb.append('=');
+        sb.append(fOffset);
+
+        return sb.toString();
+    }
+}
index 1f7b1ca1113fe186707927cba639e9f2337eaad8..726280d636a51ecc198c0776cd85a9b25e7c2ab0 100644 (file)
@@ -18,15 +18,18 @@ import org.eclipse.osgi.util.NLS;
  * @author Alexandre Montplaisir
  * @since 2.0
  */
+@SuppressWarnings("javadoc")
 public class Messages extends NLS {
 
     private static final String BUNDLE_NAME = "org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.messages"; //$NON-NLS-1$
 
-    /** Name of the DebugInfo aspect */
-    public static @Nullable String UstDebugInfoAnalysis_AspectName;
+    public static @Nullable String UstDebugInfoAnalysis_SourceAspectName;
+    public static @Nullable String UstDebugInfoAnalysis_SourceAspectHelpText;
+    public static @Nullable String UstDebugInfoAnalysis_BinaryAspectName;
+    public static @Nullable String UstDebugInfoAnalysis_BinaryAspectHelpText;
 
-    /** Help text of the DebugInfo aspect */
-    public static @Nullable String UstDebugInfoAnalysis_AspectHelpText;
+    public static @Nullable String UstDebugInfoAnalysis_Offset;
+    public static @Nullable String UstDebugInfoAnalysis_Symbol;
 
     static {
         // initialize resource bundle
diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoBinaryAspect.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/lttng2/ust/core/analysis/debuginfo/UstDebugInfoBinaryAspect.java
new file mode 100644 (file)
index 0000000..9812c71
--- /dev/null
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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.lttng2.ust.core.analysis.debuginfo;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoLoadedBinaryFile;
+import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
+import org.eclipse.tracecompass.lttng2.ust.core.trace.layout.ILttngUstEventLayout;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
+import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+/**
+ * Event aspect of UST traces that indicate the binary callsite (binary, symbol
+ * and offset) from an IP (instruction pointer) context.
+ *
+ * Unlike the {@link UstDebugInfoSourceAspect}, this information should be
+ * available even without debug information.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public class UstDebugInfoBinaryAspect implements ITmfEventAspect {
+
+    /** Singleton instance */
+    public static final UstDebugInfoBinaryAspect INSTANCE = new UstDebugInfoBinaryAspect();
+
+    private UstDebugInfoBinaryAspect() {}
+
+    @Override
+    public String getName() {
+        return nullToEmptyString(Messages.UstDebugInfoAnalysis_BinaryAspectName);
+    }
+
+    @Override
+    public String getHelpText() {
+        return nullToEmptyString(Messages.UstDebugInfoAnalysis_BinaryAspectHelpText);
+    }
+
+    @Override
+    public @Nullable BinaryCallsite resolve(ITmfEvent event) {
+        /* This aspect only supports UST traces */
+        if (!(event.getTrace() instanceof LttngUstTrace)) {
+            return null;
+        }
+
+        ILttngUstEventLayout layout = ((LttngUstTrace) event.getTrace()).getEventLayout();
+
+        /* We need both the vpid and ip contexts */
+        ITmfEventField vpidField = event.getContent().getField(layout.contextVpid());
+        ITmfEventField ipField = event.getContent().getField(layout.contextIp());
+        if (vpidField == null || ipField == null) {
+            return null;
+        }
+        Long vpid = (Long) vpidField.getValue();
+        Long ip = (Long) ipField.getValue();
+
+        /*
+         * First match the IP to the correct binary or library, by using the
+         * UstDebugInfoAnalysis.
+         */
+        UstDebugInfoAnalysisModule module =
+                TmfTraceUtils.getAnalysisModuleOfClass(event.getTrace(),
+                        UstDebugInfoAnalysisModule.class, UstDebugInfoAnalysisModule.ID);
+        if (module == null) {
+            /*
+             * The analysis is not available for this trace, we won't be
+             * able to find the information.
+             */
+            return null;
+        }
+        long ts = event.getTimestamp().getValue();
+        UstDebugInfoLoadedBinaryFile file = module.getMatchingFile(ts, vpid, ip);
+        if (file == null) {
+            return null;
+        }
+
+        long offset;
+        if (isPIC(file)) {
+            offset = (ip.longValue() - file.getBaseAddress());
+        } else {
+            /*
+             * In the case of the object being the main binary (loaded at a very
+             * low address), we must pass the actual ip address to addr2line.
+             */
+            offset = ip.longValue();
+        }
+
+        // TODO If the binary is present on the current file system, we could
+        // try to get the symbol name from it.
+
+        return new BinaryCallsite(file.getFilePath(), EMPTY_STRING, offset);
+    }
+
+    /**
+     * Return if the given file (binary or library) is Position-Independent Code
+     * or not. This indicates if addr2line considers the addresses as absolute
+     * addresses or as offsets.
+     */
+    private static boolean isPIC(UstDebugInfoLoadedBinaryFile file) {
+        /*
+         * Ghetto binary/library identification for now. It would be possible to
+         * parse the ELF binary to check if it is position-independent
+         * (-fPIC/-fPIE) or not.
+         */
+        String filePath = file.getFilePath();
+        return (filePath.endsWith(".so") || filePath.contains(".so.")); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+}
index ccb33d1fd1c11736bda92972a40b805de6539ed1..15afdd0a5e80d1bc7ae41aea9dceb274502d3f3a 100644 (file)
@@ -15,14 +15,10 @@ import java.io.File;
 
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.FileOffsetMapper;
-import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoLoadedBinaryFile;
 import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
-import org.eclipse.tracecompass.lttng2.ust.core.trace.layout.ILttngUstEventLayout;
 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
-import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
 import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
 import org.eclipse.tracecompass.tmf.core.event.lookup.TmfCallsite;
-import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
 
 import com.google.common.collect.Iterables;
 
@@ -42,12 +38,12 @@ public class UstDebugInfoSourceAspect implements ITmfEventAspect {
 
     @Override
     public String getName() {
-        return nullToEmptyString(Messages.UstDebugInfoAnalysis_AspectName);
+        return nullToEmptyString(Messages.UstDebugInfoAnalysis_SourceAspectName);
     }
 
     @Override
     public String getHelpText() {
-        return nullToEmptyString(Messages.UstDebugInfoAnalysis_AspectHelpText);
+        return nullToEmptyString(Messages.UstDebugInfoAnalysis_SourceAspectHelpText);
     }
 
     @Override
@@ -57,53 +53,16 @@ public class UstDebugInfoSourceAspect implements ITmfEventAspect {
             return null;
         }
 
-        ILttngUstEventLayout layout = ((LttngUstTrace) event.getTrace()).getEventLayout();
-
-        /* We need both the vpid and ip contexts */
-        ITmfEventField vpidField = event.getContent().getField(layout.contextVpid());
-        ITmfEventField ipField = event.getContent().getField(layout.contextIp());
-        if (vpidField == null || ipField == null) {
-            return null;
-        }
-        Long vpid = (Long) vpidField.getValue();
-        Long ip = (Long) ipField.getValue();
-
         /*
-         * First match the IP to the correct binary or library, by using the
-         * UstDebugInfoAnalysis.
+         * Resolve the binary callsite first, from there we can use the file's
+         * debug information if it is present.
          */
-        UstDebugInfoAnalysisModule module =
-                TmfTraceUtils.getAnalysisModuleOfClass(event.getTrace(),
-                        UstDebugInfoAnalysisModule.class, UstDebugInfoAnalysisModule.ID);
-        if (module == null) {
-            /*
-             * The analysis is not available for this trace, we won't be
-             * able to find the information.
-             */
-            return null;
-        }
-        long ts = event.getTimestamp().getValue();
-        UstDebugInfoLoadedBinaryFile file = module.getMatchingFile(ts, vpid, ip);
-        if (file == null) {
+        BinaryCallsite bc = UstDebugInfoBinaryAspect.INSTANCE.resolve(event);
+        if (bc == null) {
             return null;
         }
 
-        long offset;
-        if (isMainBinary(file)) {
-            /*
-             * In the case of the object being the main binary (loaded at a very
-             * low address), we must pass the actual ip address to addr2line.
-             */
-            offset = ip.longValue();
-        } else {
-            offset = (ip.longValue() - file.getBaseAddress());
-        }
-
-        if (offset < 0) {
-            throw new IllegalStateException();
-        }
-
-        Iterable<TmfCallsite> callsites = FileOffsetMapper.getCallsiteFromOffset(new File(file.getFilePath()), offset);
+        Iterable<TmfCallsite> callsites = FileOffsetMapper.getCallsiteFromOffset(new File(bc.getBinaryFilePath()), bc.getOffset());
 
         if (callsites == null || Iterables.isEmpty(callsites)) {
             return null;
@@ -115,14 +74,4 @@ public class UstDebugInfoSourceAspect implements ITmfEventAspect {
          */
         return Iterables.getLast(callsites);
     }
-
-    private static boolean isMainBinary(UstDebugInfoLoadedBinaryFile file) {
-        /*
-         * Ghetto binary/library identification for now. It would be possible to
-         * parse the ELF binary to check if it is position-independent
-         * (-fPIC/-fPIE) or not.
-         */
-        return (!file.getFilePath().endsWith(".so")); //$NON-NLS-1$
-    }
-
 }
index 1e371eb6736ef736cf346a554e4b4cc30381c999..badf1d16ef6322f2262fa9b6fdae2290a372124c 100644 (file)
@@ -7,5 +7,10 @@
 # http://www.eclipse.org/legal/epl-v10.html
 ###############################################################################
 
-UstDebugInfoAnalysis_AspectName=Source callsite
-UstDebugInfoAnalysis_AspectHelpText=The call site of this event in the source code
+UstDebugInfoAnalysis_SourceAspectName = Source callsite
+UstDebugInfoAnalysis_SourceAspectHelpText = The call site of this event in the source code
+UstDebugInfoAnalysis_BinaryAspectName = Binary callsite
+UstDebugInfoAnalysis_BinaryAspectHelpText = The call site of this event in the binary file
+
+UstDebugInfoAnalysis_Offset = offset
+UstDebugInfoAnalysis_Symbol = symbol
index 84e8f0c9c95b0d442ec01612e5470b95ab5010ea..8f159f498f7c720a349039ac1018e8e8928f1348 100644 (file)
@@ -28,6 +28,7 @@ import org.eclipse.tracecompass.internal.lttng2.ust.core.Activator;
 import org.eclipse.tracecompass.internal.lttng2.ust.core.trace.layout.LttngUst20EventLayout;
 import org.eclipse.tracecompass.internal.lttng2.ust.core.trace.layout.LttngUst27EventLayout;
 import org.eclipse.tracecompass.internal.lttng2.ust.core.trace.layout.LttngUst28EventLayout;
+import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoBinaryAspect;
 import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoSourceAspect;
 import org.eclipse.tracecompass.lttng2.ust.core.trace.layout.ILttngUstEventLayout;
 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
@@ -62,6 +63,7 @@ public class LttngUstTrace extends CtfTmfTrace {
     static {
         ImmutableSet.Builder<ITmfEventAspect> builder = ImmutableSet.builder();
         builder.addAll(CtfTmfTrace.CTF_ASPECTS);
+        builder.add(UstDebugInfoBinaryAspect.INSTANCE);
         builder.add(UstDebugInfoSourceAspect.INSTANCE);
         LTTNG_UST_ASPECTS = NonNullUtils.checkNotNull(builder.build());
     }
This page took 0.031576 seconds and 5 git commands to generate.