--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+}
* @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
--- /dev/null
+/*******************************************************************************
+ * 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$
+ }
+
+}
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;
@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
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;
*/
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$
- }
-
}
# 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
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;
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());
}