lttng: Introduce a debug-info analysis for UST traces
[deliverable/tracecompass.git] / lttng / org.eclipse.tracecompass.lttng2.ust.core / src / org / eclipse / tracecompass / lttng2 / ust / core / analysis / debuginfo / UstDebugInfoAnalysisModule.java
CommitLineData
ef7f180d
AM
1/*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9
10package org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo;
11
12import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
13
14import java.util.Collection;
15import java.util.Collections;
16import java.util.List;
17import java.util.NavigableSet;
18import java.util.Set;
19import java.util.TreeSet;
20
21import org.eclipse.jdt.annotation.Nullable;
22import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoBinaryFile;
23import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoStateProvider;
24import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
25import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
26import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
27import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
28import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
29import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
30import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
31import org.eclipse.tracecompass.tmf.core.analysis.TmfAnalysisRequirement;
32import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
33import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
34import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
35import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
36import org.eclipse.tracecompass.tmf.ctf.core.trace.CtfUtils;
37
38import com.google.common.base.Function;
39import com.google.common.base.Optional;
40import com.google.common.base.Predicate;
41import com.google.common.collect.FluentIterable;
42import com.google.common.collect.ImmutableList;
43import com.google.common.collect.Ordering;
44
45/**
46 * Analysis to provide TMF Callsite information by mapping IP (instruction
47 * pointer) contexts to address/line numbers via debug information.
48 *
49 * @author Alexandre Montplaisir
50 * @since 2.0
51 */
52public class UstDebugInfoAnalysisModule extends TmfStateSystemAnalysisModule {
53
54 /**
55 * Analysis ID, it should match that in the plugin.xml file
56 */
57 public static final String ID = "org.eclipse.linuxtools.lttng2.ust.analysis.debuginfo"; //$NON-NLS-1$
58
59 @Override
60 protected ITmfStateProvider createStateProvider() {
61 return new UstDebugInfoStateProvider(checkNotNull(getTrace()));
62 }
63
64 @Override
65 public boolean setTrace(ITmfTrace trace) throws TmfAnalysisException {
66 if (!(trace instanceof LttngUstTrace)) {
67 return false;
68 }
69 return super.setTrace(trace);
70 }
71
72 @Override
73 protected @Nullable LttngUstTrace getTrace() {
74 return (LttngUstTrace) super.getTrace();
75 }
76
77 @Override
78 public Iterable<TmfAnalysisRequirement> getAnalysisRequirements() {
79 // TODO specify actual requirements once the requirement-checking is
80 // implemented. This analysis needs "ip" and "vpid" contexts.
81 return checkNotNull(Collections.EMPTY_SET);
82 }
83
84 @Override
85 public boolean canExecute(ITmfTrace trace) {
86 /* The analysis can only work with LTTng-UST traces... */
87 if (!(trace instanceof LttngUstTrace)) {
88 return false;
89 }
90 LttngUstTrace ustTrace = (LttngUstTrace) trace;
91 String tracerName = CtfUtils.getTracerName(ustTrace);
92 int majorVersion = CtfUtils.getTracerMajorVersion(ustTrace);
93 int minorVersion = CtfUtils.getTracerMinorVersion(ustTrace);
94
95 /* ... taken with UST >= 2.8 ... */
96 if (!LttngUstTrace.TRACER_NAME.equals(tracerName)) {
97 return false;
98 }
99 if (majorVersion < 2) {
100 return false;
101 }
102 if (majorVersion == 2 && minorVersion < 8) {
103 return false;
104 }
105
106 /* ... that respect the ip/vpid contexts requirements. */
107 return super.canExecute(trace);
108 }
109
110 // ------------------------------------------------------------------------
111 // Class-specific operations
112 // ------------------------------------------------------------------------
113
114 /**
115 * Return all the binaries that were detected in the trace.
116 *
117 * @return The binaries (executables or libraries) referred to in the trace.
118 */
119 public Collection<UstDebugInfoBinaryFile> getAllBinaries() {
120 waitForCompletion();
121 ITmfStateSystem ss = checkNotNull(getStateSystem());
122
123 Set<UstDebugInfoBinaryFile> files = new TreeSet<>();
124 try {
125 ImmutableList.Builder<Integer> builder = ImmutableList.builder();
126 List<Integer> vpidQuarks = ss.getSubAttributes(-1, false);
127 for (Integer vpidQuark : vpidQuarks) {
128 builder.addAll(ss.getSubAttributes(vpidQuark, false));
129 }
130 List<Integer> baddrQuarks = builder.build();
131
132 /*
133 * For each "baddr" attribute, get the "buildId" sub-attribute,
134 * whose value is the file path.
135 */
136
137 for (Integer baddrQuark : baddrQuarks) {
138
139 List<Integer> buildIdQuarks = ss.getSubAttributes(baddrQuark, false);
140 for (Integer buildIdQuark : buildIdQuarks) {
141 String buildId = ss.getAttributeName(buildIdQuark);
142
143 /*
144 * Explore the history of this attribute "horizontally",
145 * even though there should only be one valid interval.
146 */
147 ITmfStateInterval interval = StateSystemUtils.queryUntilNonNullValue(ss, buildIdQuark, ss.getStartTime(), Long.MAX_VALUE);
148 if (interval == null) {
149 /*
150 * If we created the attribute, we should have assigned
151 * a value to it!
152 */
153 throw new IllegalStateException();
154 }
155 String filePath = interval.getStateValue().unboxStr();
156
157 files.add(new UstDebugInfoBinaryFile(filePath, buildId));
158 }
159 }
160 } catch (AttributeNotFoundException e) {
161 throw new IllegalStateException(e);
162 }
163 return files;
164 }
165
166 /**
167 * Get the binary file (executable or library) that corresponds to a given
168 * instruction pointer, at a given time.
169 *
170 * @param ts
171 * The timestamp
172 * @param vpid
173 * The VPID of the process we are querying for
174 * @param ip
175 * The instruction pointer of the trace event. Normally comes
176 * from a 'ip' context.
177 * @return The {@link UstDebugInfoBinaryFile} object, containing both the binary's path
178 * and its build ID.
179 */
180 @Nullable UstDebugInfoBinaryFile getMatchingFile(long ts, long vpid, long ip) {
181 waitForCompletion();
182 final ITmfStateSystem ss = checkNotNull(getStateSystem());
183
184 List<Integer> possibleBaddrQuarks = ss.getQuarks(String.valueOf(vpid), "*"); //$NON-NLS-1$
185
186 /* Get the most probable base address from all the known ones */
187 NavigableSet<Long> possibleBaddrs = FluentIterable.from(possibleBaddrQuarks)
188 .transform(new Function<Integer, Long>(){
189 @Override
190 public Long apply(@Nullable Integer quark) {
191 String baddrStr = ss.getAttributeName(checkNotNull(quark).intValue());
192 return checkNotNull(Long.valueOf(baddrStr));
193 }
194 }).toSortedSet(Ordering.natural());
195 final Long potentialBaddr = possibleBaddrs.floor(ip);
196
197 /* Make sure the 'ip' fits in the expected memory range */
198 try {
199 final List<ITmfStateInterval> fullState = ss.queryFullState(ts);
200
201 final int baddrQuark = ss.getQuarkAbsolute(String.valueOf(vpid), String.valueOf(potentialBaddr));
202 final long endAddr = fullState.get(baddrQuark).getStateValue().unboxLong();
203
204 if (!(ip < endAddr)) {
205 /*
206 * Not the correct memory range after all. We do not have
207 * information about the library that was loaded here.
208 */
209 return null;
210 }
211
212 /*
213 * We've found the correct base address, now to determine what
214 * library was loaded there at that time.
215 */
216 List<Integer> buildIds = ss.getSubAttributes(baddrQuark, false);
217 Optional<Integer> potentialBuildIdQuark = FluentIterable.from(buildIds).firstMatch(new Predicate<Integer>() {
218 @Override
219 public boolean apply(@Nullable Integer input) {
220 int quark = checkNotNull(input).intValue();
221 ITmfStateValue value = fullState.get(quark).getStateValue();
222 return (!value.isNull());
223 }
224 });
225
226 if (!potentialBuildIdQuark.isPresent()) {
227 /* We didn't have the information after all. */
228 return null;
229 }
230
231 /* Ok, we have everything we need! Return the information. */
232 int buildIdQuark = potentialBuildIdQuark.get().intValue();
233 String buildId = ss.getAttributeName(buildIdQuark);
234 String filePath = fullState.get(buildIdQuark).getStateValue().unboxStr();
235 return new UstDebugInfoBinaryFile(filePath, buildId);
236
237 } catch (AttributeNotFoundException e) {
238 /* We're only using quarks we've checked for. */
239 throw new IllegalStateException(e);
240 } catch (StateSystemDisposedException e) {
241 return null;
242 }
243
244 }
245
246}
This page took 0.049527 seconds and 5 git commands to generate.