1 /*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.lttng2
.ust
.core
.analysis
.debuginfo
;
12 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
14 import java
.util
.HashMap
;
17 import org
.eclipse
.jdt
.annotation
.NonNull
;
18 import org
.eclipse
.tracecompass
.internal
.lttng2
.ust
.core
.Activator
;
19 import org
.eclipse
.tracecompass
.internal
.lttng2
.ust
.core
.trace
.layout
.LttngUst28EventLayout
;
20 import org
.eclipse
.tracecompass
.lttng2
.ust
.core
.trace
.LttngUstTrace
;
21 import org
.eclipse
.tracecompass
.lttng2
.ust
.core
.trace
.layout
.ILttngUstEventLayout
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystemBuilder
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
24 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
26 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventField
;
27 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.AbstractTmfStateProvider
;
28 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfStateProvider
;
30 import com
.google
.common
.collect
.ImmutableMap
;
31 import com
.google
.common
.io
.BaseEncoding
;
34 * State provider for the debuginfo analysis. It tracks the layout of shared
35 * libraries loaded in memory by the application.
37 * The layout of the generated attribute tree will look like this:
45 * +-- baddr (value = addr range end, long)
46 * | +-- buildId (value = /path/to/library (sopath), string)
49 * | +-- buildId2 (if the same address is re-used later)
53 * The "baddr" attribute name will represent the range start as a string, and
54 * its value will be range end. If null, it means this particular library is not
55 * loaded at this location at the moment.
57 * This sits under the mtime (modification time of the file) attribute. This is
58 * to handle cases like multiple concurrent dlopen's of the same library, or the
59 * very mind-blowing edge case of a file being modified and being reloaded later
60 * on, possibly side-by-side with its previous version.
62 * Since the state system is not a spatial database, it's not really worth
63 * indexing by memory ranges, and since the amount of loaded libraries is
64 * usually small, we should afford to iterate through all mappings to find each
67 * Still, for better scalability (and for science), it could be interesting to
68 * look into storing the memory-model-over-time in something like an R-Tree.
70 * @author Alexandre Montplaisir
72 public class UstDebugInfoStateProvider
extends AbstractTmfStateProvider
{
74 /* Version of this state provider */
75 private static final int VERSION
= 1;
77 private static final int DL_DLOPEN_INDEX
= 1;
78 private static final int DL_BUILD_ID_INDEX
= 2;
79 private static final int DL_DEBUG_LINK_INDEX
= 3;
80 private static final int DL_DLCLOSE_INDEX
= 4;
81 private static final int STATEDUMP_BIN_INFO_INDEX
= 5;
82 private static final int STATEDUMP_BUILD_ID_INDEX
= 6;
83 private static final int STATEDUMP_DEBUG_LINK_INDEX
= 7;
85 private final LttngUst28EventLayout fLayout
;
86 private final Map
<String
, Integer
> fEventNames
;
89 * We need both the soinfo/dlopen event AND the matching build_id/debug_link
90 * event to get all the information about a particular binary.
92 * Between these two events, we will store the <baddr, sopath> in here.
94 private final Map
<Long
, String
> fPendingEntries
= new HashMap
<>();
102 public UstDebugInfoStateProvider(LttngUstTrace trace
) {
103 super(trace
, "Ust:DebugInfo"); //$NON-NLS-1$
104 ILttngUstEventLayout layout
= trace
.getEventLayout();
105 if (!(layout
instanceof LttngUst28EventLayout
)) {
106 /* This analysis only support UST 2.8+ traces */
107 throw new IllegalStateException("Debug info analysis was started with an incompatible trace."); //$NON-NLS-1$
109 fLayout
= (LttngUst28EventLayout
) layout
;
110 fEventNames
= buildEventNames(fLayout
);
113 private static Map
<String
, Integer
> buildEventNames(LttngUst28EventLayout layout
) {
114 ImmutableMap
.Builder
<String
, Integer
> builder
= ImmutableMap
.builder();
115 builder
.put(layout
.eventDlOpen(), DL_DLOPEN_INDEX
);
116 builder
.put(layout
.eventDlBuildId(), DL_BUILD_ID_INDEX
);
117 builder
.put(layout
.eventDlDebugLink(), DL_DEBUG_LINK_INDEX
);
118 builder
.put(layout
.eventDlClose(), DL_DLCLOSE_INDEX
);
119 builder
.put(layout
.eventStatedumpBinInfo(), STATEDUMP_BIN_INFO_INDEX
);
120 builder
.put(layout
.eventStateDumpBuildId(), STATEDUMP_BUILD_ID_INDEX
);
121 builder
.put(layout
.eventStateDumpDebugLink(), STATEDUMP_DEBUG_LINK_INDEX
);
122 return builder
.build();
126 protected void eventHandle(ITmfEvent event
) {
128 * We require the "vpid" context to build the state system. The rest of
129 * the analysis also needs the "ip" context, but the state provider part
132 ITmfEventField vpidCtx
= event
.getContent().getField(fLayout
.contextVpid());
133 if (vpidCtx
== null) {
136 final Long vpid
= (Long
) vpidCtx
.getValue();
141 final @NonNull ITmfStateSystemBuilder ss
= checkNotNull(getStateSystemBuilder());
143 String name
= event
.getName();
144 Integer index
= fEventNames
.get(name
);
146 /* Untracked event type */
149 int intIndex
= index
.intValue();
153 case DL_DLOPEN_INDEX
:
154 case STATEDUMP_BIN_INFO_INDEX
:
156 handleOpen(event
, vpid
, ss
);
160 case DL_BUILD_ID_INDEX
:
161 case STATEDUMP_BUILD_ID_INDEX
:
163 handleBuildId(event
, vpid
, ss
);
167 case DL_DEBUG_LINK_INDEX
:
168 case STATEDUMP_DEBUG_LINK_INDEX
:
169 /* Fields: Long baddr, Long crc, String filename */
175 case DL_DLCLOSE_INDEX
:
177 handleClose(event
, vpid
, ss
);
182 /* Ignore other events */
185 } catch (AttributeNotFoundException e
) {
186 Activator
.getDefault().logError("Unexpected exception in UstDebugInfoStateProvider", e
); //$NON-NLS-1$
191 * Handle opening a shared library.
193 * Uses fields: Long baddr, Long memsz, String sopath
195 private void handleOpen(ITmfEvent event
, final Long vpid
, final ITmfStateSystemBuilder ss
) throws AttributeNotFoundException
{
196 Long baddr
= (Long
) event
.getContent().getField(fLayout
.fieldBaddr()).getValue();
197 Long memsz
= (Long
) event
.getContent().getField(fLayout
.fieldMemsz()).getValue();
198 String sopath
= (String
) event
.getContent().getField(fLayout
.fieldPath()).getValue();
200 long endAddr
= baddr
.longValue() + memsz
.longValue();
201 int addrQuark
= ss
.getQuarkAbsoluteAndAdd(vpid
.toString(), baddr
.toString());
203 long ts
= event
.getTimestamp().getValue();
204 ss
.modifyAttribute(ts
, TmfStateValue
.newValueLong(endAddr
), addrQuark
);
207 * Add this library to the pending entries, the matching
208 * build_id/debug_link event will finish updating this attribute
210 fPendingEntries
.put(baddr
, checkNotNull(sopath
));
214 * Handle shared library build id
216 * Uses fields: Long baddr, long[] build_id
218 private void handleBuildId(ITmfEvent event
, final Long vpid
, final ITmfStateSystemBuilder ss
) throws AttributeNotFoundException
{
219 Long baddr
= (Long
) event
.getContent().getField(fLayout
.fieldBaddr()).getValue();
220 long[] buildIdArray
= checkNotNull((long[]) event
.getContent().getField(fLayout
.fieldBuildId()).getValue());
222 * Decode the buildID from the byte array in the trace field.
223 * Use lower-case encoding, since this is how eu-readelf
226 String buildId
= BaseEncoding
.base16().encode(longArrayToByteArray(buildIdArray
)).toLowerCase();
228 /* Retrieve the matching sopath from the pending entries */
229 String sopath
= fPendingEntries
.remove(baddr
);
230 if (sopath
== null) {
232 * We did not previously handle the initial event for this
233 * library. Lost events?
235 Activator
.getDefault().logWarning("UstDebugInfoStateProvider: Received a build_id event without a matching soinfo/dlopen one."); //$NON-NLS-1$
238 /* addrQuark should already exist */
239 int addrQuark
= ss
.getQuarkAbsolute(vpid
.toString(), baddr
.toString());
240 int buildIdQuark
= ss
.getQuarkRelativeAndAdd(addrQuark
, buildId
);
241 long ts
= event
.getTimestamp().getValue();
242 ss
.modifyAttribute(ts
, TmfStateValue
.newValueString(sopath
), buildIdQuark
);
246 * Handle shared library being closed
248 * Uses fields: Long baddr
250 private void handleClose(ITmfEvent event
, final Long vpid
, final ITmfStateSystemBuilder ss
) {
251 Long baddr
= (Long
) event
.getContent().getField(fLayout
.fieldBaddr()).getValue();
254 int quark
= ss
.getQuarkAbsolute(vpid
.toString(), baddr
.toString());
255 long ts
= event
.getTimestamp().getValue();
256 ss
.removeAttribute(ts
, quark
);
257 } catch (AttributeNotFoundException e
) {
259 * We have never seen a matching dlopen() for this
260 * dlclose(). Possible that it happened before the start of
261 * the trace, or that it was lost through lost events.
267 * Until we can use Java 8 IntStream, see
268 * http://stackoverflow.com/a/28008477/4227853.
270 private static byte[] longArrayToByteArray(long[] array
) {
271 byte[] ret
= new byte[array
.length
];
272 for (int i
= 0; i
< array
.length
; i
++) {
273 ret
[i
] = (byte) array
[i
];
279 public ITmfStateProvider
getNewInstance() {
280 return new UstDebugInfoStateProvider(getTrace());
284 public LttngUstTrace
getTrace() {
285 return (LttngUstTrace
) super.getTrace();
289 public int getVersion() {