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
;
18 import java
.util
.Optional
;
20 import java
.util
.TreeSet
;
21 import java
.util
.stream
.Collectors
;
23 import org
.eclipse
.jdt
.annotation
.Nullable
;
24 import org
.eclipse
.tracecompass
.internal
.lttng2
.ust
.core
.analysis
.debuginfo
.UstDebugInfoBinaryFile
;
25 import org
.eclipse
.tracecompass
.internal
.lttng2
.ust
.core
.analysis
.debuginfo
.UstDebugInfoLoadedBinaryFile
;
26 import org
.eclipse
.tracecompass
.internal
.lttng2
.ust
.core
.analysis
.debuginfo
.UstDebugInfoStateProvider
;
27 import org
.eclipse
.tracecompass
.lttng2
.ust
.core
.trace
.LttngUstTrace
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.StateSystemUtils
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
34 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.TmfAnalysisRequirement
;
35 import org
.eclipse
.tracecompass
.tmf
.core
.exceptions
.TmfAnalysisException
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfStateProvider
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.TmfStateSystemAnalysisModule
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
39 import org
.eclipse
.tracecompass
.tmf
.ctf
.core
.trace
.CtfUtils
;
41 import com
.google
.common
.collect
.ImmutableList
;
44 * Analysis to provide TMF Callsite information by mapping IP (instruction
45 * pointer) contexts to address/line numbers via debug information.
47 * @author Alexandre Montplaisir
50 public class UstDebugInfoAnalysisModule
extends TmfStateSystemAnalysisModule
{
53 * Analysis ID, it should match that in the plugin.xml file
55 public static final String ID
= "org.eclipse.linuxtools.lttng2.ust.analysis.debuginfo"; //$NON-NLS-1$
58 protected ITmfStateProvider
createStateProvider() {
59 return new UstDebugInfoStateProvider(checkNotNull(getTrace()));
63 public boolean setTrace(ITmfTrace trace
) throws TmfAnalysisException
{
64 if (!(trace
instanceof LttngUstTrace
)) {
67 return super.setTrace(trace
);
71 protected @Nullable LttngUstTrace
getTrace() {
72 return (LttngUstTrace
) super.getTrace();
76 public Iterable
<TmfAnalysisRequirement
> getAnalysisRequirements() {
77 // TODO specify actual requirements once the requirement-checking is
78 // implemented. This analysis needs "ip" and "vpid" contexts.
79 return checkNotNull(Collections
.EMPTY_SET
);
83 public boolean canExecute(ITmfTrace trace
) {
84 /* The analysis can only work with LTTng-UST traces... */
85 if (!(trace
instanceof LttngUstTrace
)) {
88 LttngUstTrace ustTrace
= (LttngUstTrace
) trace
;
89 String tracerName
= CtfUtils
.getTracerName(ustTrace
);
90 int majorVersion
= CtfUtils
.getTracerMajorVersion(ustTrace
);
91 int minorVersion
= CtfUtils
.getTracerMinorVersion(ustTrace
);
93 /* ... taken with UST >= 2.8 ... */
94 if (!LttngUstTrace
.TRACER_NAME
.equals(tracerName
)) {
97 if (majorVersion
< 2) {
100 if (majorVersion
== 2 && minorVersion
< 8) {
104 /* ... that respect the ip/vpid contexts requirements. */
105 return super.canExecute(trace
);
108 // ------------------------------------------------------------------------
109 // Class-specific operations
110 // ------------------------------------------------------------------------
113 * Return all the binaries that were detected in the trace.
115 * @return The binaries (executables or libraries) referred to in the trace.
117 public Collection
<UstDebugInfoBinaryFile
> getAllBinaries() {
119 ITmfStateSystem ss
= checkNotNull(getStateSystem());
121 Set
<UstDebugInfoBinaryFile
> files
= new TreeSet
<>();
123 ImmutableList
.Builder
<Integer
> builder
= ImmutableList
.builder();
124 List
<Integer
> vpidQuarks
= ss
.getSubAttributes(-1, false);
125 for (Integer vpidQuark
: vpidQuarks
) {
126 builder
.addAll(ss
.getSubAttributes(vpidQuark
, false));
128 List
<Integer
> baddrQuarks
= builder
.build();
131 * For each "baddr" attribute, get the "buildId" sub-attribute,
132 * whose value is the file path.
135 for (Integer baddrQuark
: baddrQuarks
) {
137 List
<Integer
> buildIdQuarks
= ss
.getSubAttributes(baddrQuark
, false);
138 for (Integer buildIdQuark
: buildIdQuarks
) {
139 String buildId
= ss
.getAttributeName(buildIdQuark
);
142 * Explore the history of this attribute "horizontally",
143 * even though there should only be one valid interval.
145 ITmfStateInterval interval
= StateSystemUtils
.queryUntilNonNullValue(ss
, buildIdQuark
, ss
.getStartTime(), Long
.MAX_VALUE
);
146 if (interval
== null) {
148 * If we created the attribute, we should have assigned
151 throw new IllegalStateException();
153 String filePath
= interval
.getStateValue().unboxStr();
155 files
.add(new UstDebugInfoBinaryFile(filePath
, buildId
));
158 } catch (AttributeNotFoundException e
) {
159 throw new IllegalStateException(e
);
165 * Get the binary file (executable or library) that corresponds to a given
166 * instruction pointer, at a given time.
171 * The VPID of the process we are querying for
173 * The instruction pointer of the trace event. Normally comes
174 * from a 'ip' context.
175 * @return The {@link UstDebugInfoBinaryFile} object, containing both the binary's path
178 @Nullable UstDebugInfoLoadedBinaryFile
getMatchingFile(long ts
, long vpid
, long ip
) {
180 final ITmfStateSystem ss
= checkNotNull(getStateSystem());
182 List
<Integer
> possibleBaddrQuarks
= ss
.getQuarks(String
.valueOf(vpid
), "*"); //$NON-NLS-1$
184 /* Get the most probable base address from all the known ones */
185 NavigableSet
<Long
> possibleBaddrs
= possibleBaddrQuarks
.stream()
187 String baddrStr
= ss
.getAttributeName(checkNotNull(quark
).intValue());
188 return checkNotNull(Long
.valueOf(baddrStr
));
190 .collect(Collectors
.toCollection(TreeSet
::new));
192 final Long potentialBaddr
= possibleBaddrs
.floor(ip
);
193 if (potentialBaddr
== null) {
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
= buildIds
.stream()
219 int quark
= checkNotNull(id
).intValue();
220 ITmfStateValue value
= fullState
.get(quark
).getStateValue();
221 return (!value
.isNull());
225 if (!potentialBuildIdQuark
.isPresent()) {
226 /* We didn't have the information after all. */
230 /* Ok, we have everything we need! Return the information. */
231 long baddr
= Long
.parseLong(ss
.getAttributeName(baddrQuark
));
233 int buildIdQuark
= potentialBuildIdQuark
.get().intValue();
234 String buildId
= ss
.getAttributeName(buildIdQuark
);
235 String filePath
= fullState
.get(buildIdQuark
).getStateValue().unboxStr();
236 return new UstDebugInfoLoadedBinaryFile(baddr
, filePath
, buildId
);
238 } catch (AttributeNotFoundException e
) {
239 /* We're only using quarks we've checked for. */
240 throw new IllegalStateException(e
);
241 } catch (StateSystemDisposedException e
) {