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
.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
;
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
;
47 * Analysis to provide TMF Callsite information by mapping IP (instruction
48 * pointer) contexts to address/line numbers via debug information.
50 * @author Alexandre Montplaisir
53 public class UstDebugInfoAnalysisModule
extends TmfStateSystemAnalysisModule
{
56 * Analysis ID, it should match that in the plugin.xml file
58 public static final String ID
= "org.eclipse.linuxtools.lttng2.ust.analysis.debuginfo"; //$NON-NLS-1$
61 protected ITmfStateProvider
createStateProvider() {
62 return new UstDebugInfoStateProvider(checkNotNull(getTrace()));
66 public boolean setTrace(ITmfTrace trace
) throws TmfAnalysisException
{
67 if (!(trace
instanceof LttngUstTrace
)) {
70 return super.setTrace(trace
);
74 protected @Nullable LttngUstTrace
getTrace() {
75 return (LttngUstTrace
) super.getTrace();
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
);
86 public boolean canExecute(ITmfTrace trace
) {
87 /* The analysis can only work with LTTng-UST traces... */
88 if (!(trace
instanceof LttngUstTrace
)) {
91 LttngUstTrace ustTrace
= (LttngUstTrace
) trace
;
92 String tracerName
= CtfUtils
.getTracerName(ustTrace
);
93 int majorVersion
= CtfUtils
.getTracerMajorVersion(ustTrace
);
94 int minorVersion
= CtfUtils
.getTracerMinorVersion(ustTrace
);
96 /* ... taken with UST >= 2.8 ... */
97 if (!LttngUstTrace
.TRACER_NAME
.equals(tracerName
)) {
100 if (majorVersion
< 2) {
103 if (majorVersion
== 2 && minorVersion
< 8) {
107 /* ... that respect the ip/vpid contexts requirements. */
108 return super.canExecute(trace
);
111 // ------------------------------------------------------------------------
112 // Class-specific operations
113 // ------------------------------------------------------------------------
116 * Return all the binaries that were detected in the trace.
118 * @return The binaries (executables or libraries) referred to in the trace.
120 public Collection
<UstDebugInfoBinaryFile
> getAllBinaries() {
122 ITmfStateSystem ss
= checkNotNull(getStateSystem());
124 Set
<UstDebugInfoBinaryFile
> files
= new TreeSet
<>();
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));
131 List
<Integer
> baddrQuarks
= builder
.build();
134 * For each "baddr" attribute, get the "buildId" sub-attribute,
135 * whose value is the file path.
138 for (Integer baddrQuark
: baddrQuarks
) {
140 List
<Integer
> buildIdQuarks
= ss
.getSubAttributes(baddrQuark
, false);
141 for (Integer buildIdQuark
: buildIdQuarks
) {
142 String buildId
= ss
.getAttributeName(buildIdQuark
);
145 * Explore the history of this attribute "horizontally",
146 * even though there should only be one valid interval.
148 ITmfStateInterval interval
= StateSystemUtils
.queryUntilNonNullValue(ss
, buildIdQuark
, ss
.getStartTime(), Long
.MAX_VALUE
);
149 if (interval
== null) {
151 * If we created the attribute, we should have assigned
154 throw new IllegalStateException();
156 String filePath
= interval
.getStateValue().unboxStr();
158 files
.add(new UstDebugInfoBinaryFile(filePath
, buildId
));
161 } catch (AttributeNotFoundException e
) {
162 throw new IllegalStateException(e
);
168 * Get the binary file (executable or library) that corresponds to a given
169 * instruction pointer, at a given time.
174 * The VPID of the process we are querying for
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
181 @Nullable UstDebugInfoLoadedBinaryFile
getMatchingFile(long ts
, long vpid
, long ip
) {
183 final ITmfStateSystem ss
= checkNotNull(getStateSystem());
185 List
<Integer
> possibleBaddrQuarks
= ss
.getQuarks(String
.valueOf(vpid
), "*"); //$NON-NLS-1$
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
>(){
191 public Long
apply(@Nullable Integer quark
) {
192 String baddrStr
= ss
.getAttributeName(checkNotNull(quark
).intValue());
193 return checkNotNull(Long
.valueOf(baddrStr
));
195 }).toSortedSet(Ordering
.natural());
196 final Long potentialBaddr
= possibleBaddrs
.floor(ip
);
198 /* Make sure the 'ip' fits in the expected memory range */
200 final List
<ITmfStateInterval
> fullState
= ss
.queryFullState(ts
);
202 final int baddrQuark
= ss
.getQuarkAbsolute(String
.valueOf(vpid
), String
.valueOf(potentialBaddr
));
203 final long endAddr
= fullState
.get(baddrQuark
).getStateValue().unboxLong();
205 if (!(ip
< endAddr
)) {
207 * Not the correct memory range after all. We do not have
208 * information about the library that was loaded here.
214 * We've found the correct base address, now to determine what
215 * library was loaded there at that time.
217 List
<Integer
> buildIds
= ss
.getSubAttributes(baddrQuark
, false);
218 Optional
<Integer
> potentialBuildIdQuark
= FluentIterable
.from(buildIds
).firstMatch(new Predicate
<Integer
>() {
220 public boolean apply(@Nullable Integer input
) {
221 int quark
= checkNotNull(input
).intValue();
222 ITmfStateValue value
= fullState
.get(quark
).getStateValue();
223 return (!value
.isNull());
227 if (!potentialBuildIdQuark
.isPresent()) {
228 /* We didn't have the information after all. */
232 /* Ok, we have everything we need! Return the information. */
233 long baddr
= Long
.parseLong(ss
.getAttributeName(baddrQuark
));
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
);
240 } catch (AttributeNotFoundException e
) {
241 /* We're only using quarks we've checked for. */
242 throw new IllegalStateException(e
);
243 } catch (StateSystemDisposedException e
) {