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)
47 * | +- is_pic (value = 0 or 1 (int))
51 * | +-- buildId2 (if the same address is re-used later)
56 * The "baddr" attribute name will represent the range start as a string, and
57 * its value will be range end. If null, it means this particular library is not
58 * loaded at this location at the moment.
60 * This sits under the mtime (modification time of the file) attribute. This is
61 * to handle cases like multiple concurrent dlopen's of the same library, or the
62 * very mind-blowing edge case of a file being modified and being reloaded later
63 * on, possibly side-by-side with its previous version.
65 * Since the state system is not a spatial database, it's not really worth
66 * indexing by memory ranges, and since the amount of loaded libraries is
67 * usually small, we should afford to iterate through all mappings to find each
70 * Still, for better scalability (and for science), it could be interesting to
71 * look into storing the memory-model-over-time in something like an R-Tree.
73 * @author Alexandre Montplaisir
75 public class UstDebugInfoStateProvider
extends AbstractTmfStateProvider
{
78 * Sub-attribute indicating if a given binary is PIC (position-independent
79 * code) or not. This information is present directly in the trace.
81 public static final String IS_PIC_ATTRIB
= "is_pic"; //$NON-NLS-1$
83 /* Version of this state provider */
84 private static final int VERSION
= 2;
86 private static final int DL_DLOPEN_INDEX
= 1;
87 private static final int DL_BUILD_ID_INDEX
= 2;
88 private static final int DL_DEBUG_LINK_INDEX
= 3;
89 private static final int DL_DLCLOSE_INDEX
= 4;
90 private static final int STATEDUMP_BIN_INFO_INDEX
= 5;
91 private static final int STATEDUMP_BUILD_ID_INDEX
= 6;
92 private static final int STATEDUMP_DEBUG_LINK_INDEX
= 7;
94 private final LttngUst28EventLayout fLayout
;
95 private final Map
<String
, Integer
> fEventNames
;
98 * We need both the soinfo/dlopen event AND the matching build_id/debug_link
99 * event to get all the information about a particular binary.
101 * Between these two events, we will store the <baddr, BinInfo> in here.
103 private final Map
<Long
, BinInfo
> fPendingEntries
= new HashMap
<>();
106 * Information contained in a "bin_info" event, which means a binary's path,
107 * base address, and if it is a PIC or not.
109 private static class BinInfo
{
110 public final long fBaddr
;
111 public final String fPath
;
112 public final int fIsPic
;
114 public BinInfo(long baddr
, String path
, int isPic
) {
127 public UstDebugInfoStateProvider(LttngUstTrace trace
) {
128 super(trace
, "Ust:DebugInfo"); //$NON-NLS-1$
129 ILttngUstEventLayout layout
= trace
.getEventLayout();
130 if (!(layout
instanceof LttngUst28EventLayout
)) {
131 /* This analysis only support UST 2.8+ traces */
132 throw new IllegalStateException("Debug info analysis was started with an incompatible trace."); //$NON-NLS-1$
134 fLayout
= (LttngUst28EventLayout
) layout
;
135 fEventNames
= buildEventNames(fLayout
);
138 private static Map
<String
, Integer
> buildEventNames(LttngUst28EventLayout layout
) {
139 ImmutableMap
.Builder
<String
, Integer
> builder
= ImmutableMap
.builder();
140 builder
.put(layout
.eventDlOpen(), DL_DLOPEN_INDEX
);
141 builder
.put(layout
.eventDlBuildId(), DL_BUILD_ID_INDEX
);
142 builder
.put(layout
.eventDlDebugLink(), DL_DEBUG_LINK_INDEX
);
143 builder
.put(layout
.eventDlClose(), DL_DLCLOSE_INDEX
);
144 builder
.put(layout
.eventStatedumpBinInfo(), STATEDUMP_BIN_INFO_INDEX
);
145 builder
.put(layout
.eventStateDumpBuildId(), STATEDUMP_BUILD_ID_INDEX
);
146 builder
.put(layout
.eventStateDumpDebugLink(), STATEDUMP_DEBUG_LINK_INDEX
);
147 return builder
.build();
151 protected void eventHandle(ITmfEvent event
) {
153 * We require the "vpid" context to build the state system. The rest of
154 * the analysis also needs the "ip" context, but the state provider part
157 ITmfEventField vpidCtx
= event
.getContent().getField(fLayout
.contextVpid());
158 if (vpidCtx
== null) {
161 final Long vpid
= (Long
) vpidCtx
.getValue();
166 final @NonNull ITmfStateSystemBuilder ss
= checkNotNull(getStateSystemBuilder());
168 String name
= event
.getName();
169 Integer index
= fEventNames
.get(name
);
171 /* Untracked event type */
174 int intIndex
= index
.intValue();
178 case DL_DLOPEN_INDEX
:
179 case STATEDUMP_BIN_INFO_INDEX
:
181 handleOpen(event
, vpid
, ss
);
185 case DL_BUILD_ID_INDEX
:
186 case STATEDUMP_BUILD_ID_INDEX
:
188 handleBuildId(event
, vpid
, ss
);
192 case DL_DEBUG_LINK_INDEX
:
193 case STATEDUMP_DEBUG_LINK_INDEX
:
194 /* Fields: Long baddr, Long crc, String filename */
200 case DL_DLCLOSE_INDEX
:
202 handleClose(event
, vpid
, ss
);
207 /* Ignore other events */
210 } catch (AttributeNotFoundException e
) {
211 Activator
.getDefault().logError("Unexpected exception in UstDebugInfoStateProvider", e
); //$NON-NLS-1$
216 * Handle opening a shared library.
218 * Uses fields: Long baddr, Long memsz, String sopath
220 private void handleOpen(ITmfEvent event
, final Long vpid
, final ITmfStateSystemBuilder ss
) {
221 Long baddr
= (Long
) event
.getContent().getField(fLayout
.fieldBaddr()).getValue();
222 Long memsz
= (Long
) event
.getContent().getField(fLayout
.fieldMemsz()).getValue();
223 String sopath
= (String
) event
.getContent().getField(fLayout
.fieldPath()).getValue();
225 /* "dlopen" events do not have a "is_pic" field, they always refer to PIC libs */
226 ITmfEventField isPicField
= event
.getContent().getField(fLayout
.fieldIsPic());
227 Long isPicVal
= (isPicField
== null ?
1L : (Long
) isPicField
.getValue());
229 long endAddr
= baddr
.longValue() + memsz
.longValue();
230 int addrQuark
= ss
.getQuarkAbsoluteAndAdd(vpid
.toString(), baddr
.toString());
232 long ts
= event
.getTimestamp().getValue();
233 ss
.modifyAttribute(ts
, TmfStateValue
.newValueLong(endAddr
), addrQuark
);
236 * Add this library to the pending entries, the matching
237 * build_id/debug_link event will finish updating this attribute
239 BinInfo binInfo
= new BinInfo(baddr
, checkNotNull(sopath
), isPicVal
.intValue());
240 fPendingEntries
.put(binInfo
.fBaddr
, binInfo
);
244 * Handle shared library build id
246 * Uses fields: Long baddr, long[] build_id
248 private void handleBuildId(ITmfEvent event
, final Long vpid
, final ITmfStateSystemBuilder ss
) throws AttributeNotFoundException
{
249 Long baddr
= (Long
) event
.getContent().getField(fLayout
.fieldBaddr()).getValue();
250 long[] buildIdArray
= checkNotNull((long[]) event
.getContent().getField(fLayout
.fieldBuildId()).getValue());
252 * Decode the buildID from the byte array in the trace field.
253 * Use lower-case encoding, since this is how eu-readelf
256 String buildId
= BaseEncoding
.base16().encode(longArrayToByteArray(buildIdArray
)).toLowerCase();
258 /* Retrieve the matching sopath from the pending entries */
259 BinInfo binInfo
= fPendingEntries
.remove(baddr
);
260 if (binInfo
== null) {
262 * We did not previously handle the initial event for this
263 * library. Lost events?
265 Activator
.getDefault().logWarning("UstDebugInfoStateProvider: Received a build_id event without a matching soinfo/dlopen one."); //$NON-NLS-1$
268 /* addrQuark should already exist */
269 int addrQuark
= ss
.getQuarkAbsolute(vpid
.toString(), baddr
.toString());
271 /* build-id attribute */
272 int buildIdQuark
= ss
.getQuarkRelativeAndAdd(addrQuark
, buildId
);
273 long ts
= event
.getTimestamp().getValue();
274 ss
.modifyAttribute(ts
, TmfStateValue
.newValueString(binInfo
.fPath
), buildIdQuark
);
276 /* "is_pic" sub-attribute */
277 int isPicQuark
= ss
.getQuarkRelativeAndAdd(buildIdQuark
, IS_PIC_ATTRIB
);
278 ss
.modifyAttribute(ts
, TmfStateValue
.newValueInt(binInfo
.fIsPic
), isPicQuark
);
282 * Handle shared library being closed
284 * Uses fields: Long baddr
286 private void handleClose(ITmfEvent event
, final Long vpid
, final ITmfStateSystemBuilder ss
) {
287 Long baddr
= (Long
) event
.getContent().getField(fLayout
.fieldBaddr()).getValue();
290 int quark
= ss
.getQuarkAbsolute(vpid
.toString(), baddr
.toString());
291 long ts
= event
.getTimestamp().getValue();
292 ss
.removeAttribute(ts
, quark
);
293 } catch (AttributeNotFoundException e
) {
295 * We have never seen a matching dlopen() for this
296 * dlclose(). Possible that it happened before the start of
297 * the trace, or that it was lost through lost events.
303 * Until we can use Java 8 IntStream, see
304 * http://stackoverflow.com/a/28008477/4227853.
306 private static byte[] longArrayToByteArray(long[] array
) {
307 byte[] ret
= new byte[array
.length
];
308 for (int i
= 0; i
< array
.length
; i
++) {
309 ret
[i
] = (byte) array
[i
];
315 public ITmfStateProvider
getNewInstance() {
316 return new UstDebugInfoStateProvider(getTrace());
320 public LttngUstTrace
getTrace() {
321 return (LttngUstTrace
) super.getTrace();
325 public int getVersion() {