90bba3bd3b2902fd08214b55fbfb164cbe0fb977
[deliverable/tracecompass.git] / lttng / org.eclipse.tracecompass.lttng2.ust.core / src / org / eclipse / tracecompass / internal / lttng2 / ust / core / analysis / debuginfo / UstDebugInfoStateProvider.java
1 /*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
3 *
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 *******************************************************************************/
9
10 package org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo;
11
12 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
13
14 import java.util.HashMap;
15 import java.util.Map;
16
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;
29
30 import com.google.common.collect.ImmutableMap;
31 import com.google.common.io.BaseEncoding;
32
33 /**
34 * State provider for the debuginfo analysis. It tracks the layout of shared
35 * libraries loaded in memory by the application.
36 *
37 * The layout of the generated attribute tree will look like this:
38 *
39 * <pre>
40 * * [root]
41 * +-- 1000
42 * +-- 2000
43 * ...
44 * +-- 3000 (VPIDs)
45 * +-- baddr (value = addr range end, long)
46 * | +-- buildId (value = /path/to/library (sopath), string)
47 * +-- baddr
48 * | +-- buildId1
49 * | +-- buildId2 (if the same address is re-used later)
50 * ...
51 * </pre>
52 *
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.
56 *
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.
61 *
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
65 * match.
66 *
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.
69 *
70 * @author Alexandre Montplaisir
71 */
72 public class UstDebugInfoStateProvider extends AbstractTmfStateProvider {
73
74 /* Version of this state provider */
75 private static final int VERSION = 1;
76
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;
84
85 private final LttngUst28EventLayout fLayout;
86 private final Map<String, Integer> fEventNames;
87
88 /**
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.
91 *
92 * Between these two events, we will store the <baddr, sopath> in here.
93 */
94 private final Map<Long, String> fPendingEntries = new HashMap<>();
95
96 /**
97 * Constructor
98 *
99 * @param trace
100 * trace
101 */
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$
108 }
109 fLayout = (LttngUst28EventLayout) layout;
110 fEventNames = buildEventNames(fLayout);
111 }
112
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();
123 }
124
125 @Override
126 protected void eventHandle(ITmfEvent event) {
127 /*
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
130 * does not.
131 */
132 ITmfEventField vpidCtx = event.getContent().getField(fLayout.contextVpid());
133 if (vpidCtx == null) {
134 return;
135 }
136 final Long vpid = (Long) vpidCtx.getValue();
137 if (vpid == null) {
138 return;
139 }
140
141 final @NonNull ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
142
143 String name = event.getName();
144 Integer index = fEventNames.get(name);
145 if (index == null) {
146 /* Untracked event type */
147 return;
148 }
149 int intIndex = index.intValue();
150
151 try {
152 switch (intIndex) {
153 case DL_DLOPEN_INDEX:
154 case STATEDUMP_BIN_INFO_INDEX:
155 {
156 handleOpen(event, vpid, ss);
157 break;
158 }
159
160 case DL_BUILD_ID_INDEX:
161 case STATEDUMP_BUILD_ID_INDEX:
162 {
163 handleBuildId(event, vpid, ss);
164 break;
165 }
166
167 case DL_DEBUG_LINK_INDEX:
168 case STATEDUMP_DEBUG_LINK_INDEX:
169 /* Fields: Long baddr, Long crc, String filename */
170 {
171 // TODO NYI
172 break;
173 }
174
175 case DL_DLCLOSE_INDEX:
176 {
177 handleClose(event, vpid, ss);
178 break;
179 }
180
181 default:
182 /* Ignore other events */
183 break;
184 }
185 } catch (AttributeNotFoundException e) {
186 Activator.getDefault().logError("Unexpected exception in UstDebugInfoStateProvider", e); //$NON-NLS-1$
187 }
188 }
189
190 /**
191 * Handle opening a shared library.
192 *
193 * Uses fields: Long baddr, Long memsz, String sopath
194 */
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();
199
200 long endAddr = baddr.longValue() + memsz.longValue();
201 int addrQuark = ss.getQuarkAbsoluteAndAdd(vpid.toString(), baddr.toString());
202
203 long ts = event.getTimestamp().getValue();
204 ss.modifyAttribute(ts, TmfStateValue.newValueLong(endAddr), addrQuark);
205
206 /*
207 * Add this library to the pending entries, the matching
208 * build_id/debug_link event will finish updating this attribute
209 */
210 fPendingEntries.put(baddr, checkNotNull(sopath));
211 }
212
213 /**
214 * Handle shared library build id
215 *
216 * Uses fields: Long baddr, long[] build_id
217 */
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());
221 /*
222 * Decode the buildID from the byte array in the trace field.
223 * Use lower-case encoding, since this is how eu-readelf
224 * displays it.
225 */
226 String buildId = BaseEncoding.base16().encode(longArrayToByteArray(buildIdArray)).toLowerCase();
227
228 /* Retrieve the matching sopath from the pending entries */
229 String sopath = fPendingEntries.remove(baddr);
230 if (sopath == null) {
231 /*
232 * We did not previously handle the initial event for this
233 * library. Lost events?
234 */
235 Activator.getDefault().logWarning("UstDebugInfoStateProvider: Received a build_id event without a matching soinfo/dlopen one."); //$NON-NLS-1$
236 return;
237 }
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);
243 }
244
245 /**
246 * Handle shared library being closed
247 *
248 * Uses fields: Long baddr
249 */
250 private void handleClose(ITmfEvent event, final Long vpid, final ITmfStateSystemBuilder ss) {
251 Long baddr = (Long) event.getContent().getField(fLayout.fieldBaddr()).getValue();
252
253 try {
254 int quark = ss.getQuarkAbsolute(vpid.toString(), baddr.toString());
255 long ts = event.getTimestamp().getValue();
256 ss.removeAttribute(ts, quark);
257 } catch (AttributeNotFoundException e) {
258 /*
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.
262 */
263 }
264 }
265
266 /**
267 * Until we can use Java 8 IntStream, see
268 * http://stackoverflow.com/a/28008477/4227853.
269 */
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];
274 }
275 return ret;
276 }
277
278 @Override
279 public ITmfStateProvider getNewInstance() {
280 return new UstDebugInfoStateProvider(getTrace());
281 }
282
283 @Override
284 public LttngUstTrace getTrace() {
285 return (LttngUstTrace) super.getTrace();
286 }
287
288 @Override
289 public int getVersion() {
290 return VERSION;
291 }
292
293 }
This page took 0.04012 seconds and 4 git commands to generate.