1 /*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
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 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.lttng2
.ust
.core
.analysis
.debuginfo
;
12 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
14 import java
.util
.Collection
;
15 import java
.util
.Collections
;
16 import java
.util
.List
;
17 import java
.util
.NavigableSet
;
19 import java
.util
.TreeSet
;
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
.UstDebugInfoStateProvider
;
24 import org
.eclipse
.tracecompass
.lttng2
.ust
.core
.trace
.LttngUstTrace
;
25 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
26 import org
.eclipse
.tracecompass
.statesystem
.core
.StateSystemUtils
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
31 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.TmfAnalysisRequirement
;
32 import org
.eclipse
.tracecompass
.tmf
.core
.exceptions
.TmfAnalysisException
;
33 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfStateProvider
;
34 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.TmfStateSystemAnalysisModule
;
35 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
36 import org
.eclipse
.tracecompass
.tmf
.ctf
.core
.trace
.CtfUtils
;
38 import com
.google
.common
.base
.Function
;
39 import com
.google
.common
.base
.Optional
;
40 import com
.google
.common
.base
.Predicate
;
41 import com
.google
.common
.collect
.FluentIterable
;
42 import com
.google
.common
.collect
.ImmutableList
;
43 import com
.google
.common
.collect
.Ordering
;
46 * Analysis to provide TMF Callsite information by mapping IP (instruction
47 * pointer) contexts to address/line numbers via debug information.
49 * @author Alexandre Montplaisir
52 public class UstDebugInfoAnalysisModule
extends TmfStateSystemAnalysisModule
{
55 * Analysis ID, it should match that in the plugin.xml file
57 public static final String ID
= "org.eclipse.linuxtools.lttng2.ust.analysis.debuginfo"; //$NON-NLS-1$
60 protected ITmfStateProvider
createStateProvider() {
61 return new UstDebugInfoStateProvider(checkNotNull(getTrace()));
65 public boolean setTrace(ITmfTrace trace
) throws TmfAnalysisException
{
66 if (!(trace
instanceof LttngUstTrace
)) {
69 return super.setTrace(trace
);
73 protected @Nullable LttngUstTrace
getTrace() {
74 return (LttngUstTrace
) super.getTrace();
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
);
85 public boolean canExecute(ITmfTrace trace
) {
86 /* The analysis can only work with LTTng-UST traces... */
87 if (!(trace
instanceof LttngUstTrace
)) {
90 LttngUstTrace ustTrace
= (LttngUstTrace
) trace
;
91 String tracerName
= CtfUtils
.getTracerName(ustTrace
);
92 int majorVersion
= CtfUtils
.getTracerMajorVersion(ustTrace
);
93 int minorVersion
= CtfUtils
.getTracerMinorVersion(ustTrace
);
95 /* ... taken with UST >= 2.8 ... */
96 if (!LttngUstTrace
.TRACER_NAME
.equals(tracerName
)) {
99 if (majorVersion
< 2) {
102 if (majorVersion
== 2 && minorVersion
< 8) {
106 /* ... that respect the ip/vpid contexts requirements. */
107 return super.canExecute(trace
);
110 // ------------------------------------------------------------------------
111 // Class-specific operations
112 // ------------------------------------------------------------------------
115 * Return all the binaries that were detected in the trace.
117 * @return The binaries (executables or libraries) referred to in the trace.
119 public Collection
<UstDebugInfoBinaryFile
> getAllBinaries() {
121 ITmfStateSystem ss
= checkNotNull(getStateSystem());
123 Set
<UstDebugInfoBinaryFile
> files
= new TreeSet
<>();
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));
130 List
<Integer
> baddrQuarks
= builder
.build();
133 * For each "baddr" attribute, get the "buildId" sub-attribute,
134 * whose value is the file path.
137 for (Integer baddrQuark
: baddrQuarks
) {
139 List
<Integer
> buildIdQuarks
= ss
.getSubAttributes(baddrQuark
, false);
140 for (Integer buildIdQuark
: buildIdQuarks
) {
141 String buildId
= ss
.getAttributeName(buildIdQuark
);
144 * Explore the history of this attribute "horizontally",
145 * even though there should only be one valid interval.
147 ITmfStateInterval interval
= StateSystemUtils
.queryUntilNonNullValue(ss
, buildIdQuark
, ss
.getStartTime(), Long
.MAX_VALUE
);
148 if (interval
== null) {
150 * If we created the attribute, we should have assigned
153 throw new IllegalStateException();
155 String filePath
= interval
.getStateValue().unboxStr();
157 files
.add(new UstDebugInfoBinaryFile(filePath
, buildId
));
160 } catch (AttributeNotFoundException e
) {
161 throw new IllegalStateException(e
);
167 * Get the binary file (executable or library) that corresponds to a given
168 * instruction pointer, at a given time.
173 * The VPID of the process we are querying for
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
180 @Nullable UstDebugInfoBinaryFile
getMatchingFile(long ts
, long vpid
, long ip
) {
182 final ITmfStateSystem ss
= checkNotNull(getStateSystem());
184 List
<Integer
> possibleBaddrQuarks
= ss
.getQuarks(String
.valueOf(vpid
), "*"); //$NON-NLS-1$
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
>(){
190 public Long
apply(@Nullable Integer quark
) {
191 String baddrStr
= ss
.getAttributeName(checkNotNull(quark
).intValue());
192 return checkNotNull(Long
.valueOf(baddrStr
));
194 }).toSortedSet(Ordering
.natural());
195 final Long potentialBaddr
= possibleBaddrs
.floor(ip
);
197 /* Make sure the 'ip' fits in the expected memory range */
199 final List
<ITmfStateInterval
> fullState
= ss
.queryFullState(ts
);
201 final int baddrQuark
= ss
.getQuarkAbsolute(String
.valueOf(vpid
), String
.valueOf(potentialBaddr
));
202 final long endAddr
= fullState
.get(baddrQuark
).getStateValue().unboxLong();
204 if (!(ip
< endAddr
)) {
206 * Not the correct memory range after all. We do not have
207 * information about the library that was loaded here.
213 * We've found the correct base address, now to determine what
214 * library was loaded there at that time.
216 List
<Integer
> buildIds
= ss
.getSubAttributes(baddrQuark
, false);
217 Optional
<Integer
> potentialBuildIdQuark
= FluentIterable
.from(buildIds
).firstMatch(new Predicate
<Integer
>() {
219 public boolean apply(@Nullable Integer input
) {
220 int quark
= checkNotNull(input
).intValue();
221 ITmfStateValue value
= fullState
.get(quark
).getStateValue();
222 return (!value
.isNull());
226 if (!potentialBuildIdQuark
.isPresent()) {
227 /* We didn't have the information after all. */
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
);
237 } catch (AttributeNotFoundException e
) {
238 /* We're only using quarks we've checked for. */
239 throw new IllegalStateException(e
);
240 } catch (StateSystemDisposedException e
) {