1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 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
.OptionalLong
;
19 import java
.util
.TreeSet
;
21 import org
.eclipse
.jdt
.annotation
.NonNull
;
22 import org
.eclipse
.jdt
.annotation
.Nullable
;
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
.exceptions
.TimeRangeException
;
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
.requirements
.TmfAbstractAnalysisRequirement
;
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
.annotations
.VisibleForTesting
;
40 import com
.google
.common
.collect
.ImmutableList
;
43 * Analysis to provide TMF Callsite information by mapping IP (instruction
44 * pointer) contexts to address/line numbers via debug information.
46 * @author Alexandre Montplaisir
49 public class UstDebugInfoAnalysisModule
extends TmfStateSystemAnalysisModule
{
52 * Analysis ID, it should match that in the plugin.xml file
54 public static final String ID
= "org.eclipse.linuxtools.lttng2.ust.analysis.debuginfo"; //$NON-NLS-1$
57 protected ITmfStateProvider
createStateProvider() {
58 return new UstDebugInfoStateProvider(checkNotNull(getTrace()));
62 public boolean setTrace(ITmfTrace trace
) throws TmfAnalysisException
{
63 if (!(trace
instanceof LttngUstTrace
)) {
66 return super.setTrace(trace
);
74 public LttngUstTrace
getTrace() {
75 return (LttngUstTrace
) super.getTrace();
79 public Iterable
<TmfAbstractAnalysisRequirement
> getAnalysisRequirements() {
80 // TODO specify actual requirements once the requirement-checking is
81 // implemented. This analysis needs "ip" and "vpid" contexts.
82 return 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() {
121 ITmfStateSystem ss
= getStateSystem();
123 /* State system might not yet be initialized */
124 return Collections
.EMPTY_SET
;
127 final @NonNull Set
<UstDebugInfoBinaryFile
> files
= new TreeSet
<>();
128 ImmutableList
.Builder
<Integer
> builder
= ImmutableList
.builder();
129 List
<Integer
> vpidQuarks
= ss
.getSubAttributes(ITmfStateSystem
.ROOT_ATTRIBUTE
, false);
130 for (Integer vpidQuark
: vpidQuarks
) {
131 builder
.addAll(ss
.getSubAttributes(vpidQuark
, false));
133 List
<Integer
> baddrQuarks
= builder
.build();
136 for (Integer baddrQuark
: baddrQuarks
) {
137 int buildIdQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.BUILD_ID_ATTRIB
);
138 int debugLinkQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.DEBUG_LINK_ATTRIB
);
139 int pathQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.PATH_ATTRIB
);
140 int isPICQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.IS_PIC_ATTRIB
);
141 long ts
= ss
.getStartTime();
144 * Iterate over each mapping there ever was at this base
147 ITmfStateInterval interval
= StateSystemUtils
.queryUntilNonNullValue(ss
, baddrQuark
, ts
, Long
.MAX_VALUE
);
148 while (interval
!= null) {
149 ts
= interval
.getStartTime();
151 ITmfStateValue filePathStateValue
= ss
.querySingleState(ts
, pathQuark
).getStateValue();
152 String filePath
= filePathStateValue
.unboxStr();
154 ITmfStateValue buildIdStateValue
= ss
.querySingleState(ts
, buildIdQuark
).getStateValue();
155 String buildId
= unboxStrOrNull(buildIdStateValue
);
157 ITmfStateValue debuglinkStateValue
= ss
.querySingleState(ts
, debugLinkQuark
).getStateValue();
158 String debugLink
= unboxStrOrNull(debuglinkStateValue
);
160 ITmfStateValue isPICStateValue
= ss
.querySingleState(ts
, isPICQuark
).getStateValue();
161 Boolean isPIC
= isPICStateValue
.unboxInt() != 0;
163 files
.add(new UstDebugInfoBinaryFile(filePath
, buildId
, debugLink
, isPIC
));
166 * Go one past the end of the interval, and perform the
167 * query again to find the next mapping at this address.
169 ts
= interval
.getEndTime() + 1;
170 interval
= StateSystemUtils
.queryUntilNonNullValue(ss
, baddrQuark
, ts
, Long
.MAX_VALUE
);
173 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException e
) {
174 /* Oh well, such is life. */
180 * Get the binary file (executable or library) that corresponds to a given
181 * instruction pointer, at a given time.
186 * The VPID of the process we are querying for
188 * The instruction pointer of the trace event. Normally comes
189 * from a 'ip' context.
190 * @return A {@link UstDebugInfoLoadedBinaryFile} object, describing the
191 * binary file and its base address.
192 * @noreference Meant to be used internally by
193 * {@link UstDebugInfoBinaryAspect} only.
196 public @Nullable UstDebugInfoLoadedBinaryFile
getMatchingFile(long ts
, long vpid
, long ip
) {
198 final ITmfStateSystem ss
= getStateSystem();
200 /* State system might not yet be initialized */
204 List
<Integer
> possibleBaddrQuarks
= ss
.getQuarks(String
.valueOf(vpid
), "*"); //$NON-NLS-1$
205 List
<ITmfStateInterval
> state
= ss
.queryFullState(ts
);
207 /* Get the most probable base address from all the known ones */
208 OptionalLong potentialBaddr
= possibleBaddrQuarks
.stream()
210 /* Keep only currently (at ts) mapped objects. */
211 ITmfStateValue value
= state
.get(quark
).getStateValue();
212 return value
.getType() == ITmfStateValue
.Type
.INTEGER
&& value
.unboxInt() == 1;
214 .map(quark
-> ss
.getAttributeName(quark
.intValue()))
215 .mapToLong(baddrStr
-> Long
.parseLong(baddrStr
))
216 .filter(baddr
-> baddr
<= ip
)
219 if (!potentialBaddr
.isPresent()) {
223 long baddr
= potentialBaddr
.getAsLong();
224 final int baddrQuark
= ss
.getQuarkAbsolute(String
.valueOf(vpid
),
225 String
.valueOf(baddr
));
227 final int memszQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.MEMSZ_ATTRIB
);
228 final long memsz
= state
.get(memszQuark
).getStateValue().unboxLong();
230 /* Make sure the 'ip' fits the range of this object. */
231 if (!(ip
< baddr
+ memsz
)) {
233 * Not the correct memory range after all. We do not have
234 * information about the library that was loaded here.
239 final int pathQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.PATH_ATTRIB
);
240 String filePath
= state
.get(pathQuark
).getStateValue().unboxStr();
242 final int buildIdQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.BUILD_ID_ATTRIB
);
243 ITmfStateValue buildIdValue
= state
.get(buildIdQuark
).getStateValue();
244 String buildId
= unboxStrOrNull(buildIdValue
);
246 final int debugLinkQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.DEBUG_LINK_ATTRIB
);
247 ITmfStateValue debugLinkValue
= state
.get(debugLinkQuark
).getStateValue();
248 String debugLink
= unboxStrOrNull(debugLinkValue
);
250 final int isPicQuark
= ss
.getQuarkRelative(baddrQuark
, UstDebugInfoStateProvider
.IS_PIC_ATTRIB
);
251 boolean isPic
= state
.get(isPicQuark
).getStateValue().unboxInt() != 0;
253 return new UstDebugInfoLoadedBinaryFile(baddr
, filePath
, buildId
, debugLink
, isPic
);
255 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException e
) {
256 /* Either the data is not available yet, or incomplete. */
261 private static @Nullable String
unboxStrOrNull(ITmfStateValue value
) {
262 return (value
.isNull() ?
null : value
.unboxStr());