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