import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoBinaryFile;
import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoAnalysisModule;
import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoBinaryAspect;
+import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoBinaryFile;
+import org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo.UstDebugInfoLoadedBinaryFile;
import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstEvent;
import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
*/
public class UstDebugInfoAnalysisModuleTest {
- private static final @NonNull CtfTestTrace TEST_TRACE = CtfTestTrace.DEBUG_INFO3;
+ private static final @NonNull CtfTestTrace REAL_TEST_TRACE = CtfTestTrace.DEBUG_INFO4;
+ private static final @NonNull CtfTestTrace SYNTH_EXEC_TRACE = CtfTestTrace.DEBUG_INFO_SYNTH_EXEC;
+ private static final @NonNull CtfTestTrace SYNTH_TWO_PROCESSES_TRACE = CtfTestTrace.DEBUG_INFO_SYNTH_TWO_PROCESSES;
+ private static final @NonNull CtfTestTrace SYNTH_BUILDID_DEBUGLINK_TRACE = CtfTestTrace.DEBUG_INFO_SYNTH_BUILDID_DEBUGLINK;
private static final @NonNull CtfTestTrace INVALID_TRACE = CtfTestTrace.CYG_PROFILE;
private LttngUstTrace fTrace;
@Before
public void setup() {
fModule = new UstDebugInfoAnalysisModule();
- fTrace = new LttngUstTrace();
- try {
- fTrace.initTrace(null, CtfTmfTestTraceUtils.getTrace(TEST_TRACE).getPath(), CtfTmfEvent.class);
- } catch (TmfTraceException e) {
- /* Should not happen if tracesExist() passed */
- throw new RuntimeException(e);
- }
}
/**
*/
@After
public void tearDown() {
- fTrace.dispose();
+ if (fTrace != null) {
+ fTrace.dispose();
+ fTrace = null;
+ }
+
fModule.dispose();
- fTrace = null;
fModule = null;
}
+ private @NonNull LttngUstTrace setupTrace(@NonNull CtfTestTrace testTrace) {
+ LttngUstTrace trace = new LttngUstTrace();
+ try {
+ trace.initTrace(null, CtfTmfTestTraceUtils.getTrace(testTrace).getPath(), CtfTmfEvent.class);
+ } catch (TmfTraceException e) {
+ fail(e.getMessage());
+ }
+ fTrace = trace;
+ return trace;
+ }
+
/**
* Test for {@link UstDebugInfoAnalysisModule#getAnalysisRequirements()}
*/
*/
@Test
public void testCanExecute() {
- assertNotNull(fTrace);
- assertTrue(fModule.canExecute(fTrace));
+ LttngUstTrace trace = setupTrace(REAL_TEST_TRACE);
+ assertTrue(fModule.canExecute(trace));
}
/**
* Test that the analysis correctly refuses to execute on an invalid trace
* (LTTng-UST < 2.8 in this case).
- *
- * @throws TmfTraceException
- * Should not happen
*/
@Test
- public void testCannotExcecute() throws TmfTraceException {
- LttngUstTrace invalidTrace = new LttngUstTrace();
- invalidTrace.initTrace(null, CtfTmfTestTraceUtils.getTrace(INVALID_TRACE).getPath(), CtfTmfEvent.class);
+ public void testCannotExcecute() {
+ LttngUstTrace invalidTrace = setupTrace(INVALID_TRACE);
assertFalse(fModule.canExecute(invalidTrace));
-
- invalidTrace.dispose();
}
private void executeModule() {
*/
@Test
public void testExecution() {
+ setupTrace(REAL_TEST_TRACE);
executeModule();
ITmfStateSystem ss = fModule.getStateSystem();
assertNotNull(ss);
*/
@Test
public void testBinaryCallsites() {
- assertNotNull(fTrace);
+ LttngUstTrace trace = setupTrace(REAL_TEST_TRACE);
+
/*
* Fake a "trace opened" signal, so that the relevant analyses are
* started.
*/
- TmfTraceOpenedSignal signal = new TmfTraceOpenedSignal(this, fTrace, null);
+ TmfTraceOpenedSignal signal = new TmfTraceOpenedSignal(this, trace, null);
TmfSignalManager.dispatchSignal(signal);
/* Send a request to get the 3 events we are interested in */
List<@NonNull LttngUstEvent> events = new ArrayList<>();
- TmfEventRequest request = new TmfEventRequest(LttngUstEvent.class, 287, 3, ExecutionType.FOREGROUND) {
+ TmfEventRequest request = new TmfEventRequest(LttngUstEvent.class, 31, 1, ExecutionType.FOREGROUND) {
@Override
public void handleData(ITmfEvent event) {
super.handleData(event);
events.add((LttngUstEvent) event);
}
};
- fTrace.sendRequest(request);
+ trace.sendRequest(request);
try {
request.waitForCompletion();
} catch (InterruptedException e) {
final UstDebugInfoBinaryAspect aspect = UstDebugInfoBinaryAspect.INSTANCE;
String actual = checkNotNull(aspect.resolve(events.get(0))).toString();
- String expected = "/home/alexandre/src/lttng-project/lttng/trace-utils/dynamicLinking/libhello.so+0x15ae";
+ String expected = "/home/simark/src/babeltrace/tests/debug-info-data/libhello_so+0x14d4";
assertEquals(expected, actual);
+ }
- actual = checkNotNull(aspect.resolve(events.get(1))).toString();
- expected = "/home/alexandre/src/lttng-project/lttng/trace-utils/dynamicLinking/libhello.so+0x1680";
- assertEquals(expected, actual);
+ /**
+ * Test the analysis with a test trace doing an "exec" system call.
+ */
+ @Test
+ public void testExec() {
+ UstDebugInfoLoadedBinaryFile matchingFile, expected;
- actual = checkNotNull(aspect.resolve(events.get(2))).toString();
- expected = "/home/alexandre/src/lttng-project/lttng/trace-utils/dynamicLinking/libhello.so+0x1745";
- assertEquals(expected, actual);
+ int vpid = 1337;
+
+ setupTrace(SYNTH_EXEC_TRACE);
+ executeModule();
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x400000, "/tmp/foo", null, null, false);
+ matchingFile = fModule.getMatchingFile(4000000, vpid, 0x400100);
+ assertEquals(expected, matchingFile);
+
+ expected = null;
+ matchingFile = fModule.getMatchingFile(8000000, vpid, 0x400100);
+ assertEquals(expected, matchingFile);
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x500000, "/tmp/bar", null, null, false);
+ matchingFile = fModule.getMatchingFile(9000000, vpid, 0x500100);
+ assertEquals(expected, matchingFile);
+ }
+
+ /**
+ * Test the analysis with a test trace with two processes doing a statedump
+ * simultaneously.
+ */
+ @Test
+ public void testTwoProcesses() {
+ UstDebugInfoLoadedBinaryFile matchingFile, expected;
+ int vpid1 = 1337;
+ int vpid2 = 2001;
+
+ setupTrace(SYNTH_TWO_PROCESSES_TRACE);
+ executeModule();
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x400000, "/tmp/foo", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "/tmp/debuglink1", false);
+ matchingFile = fModule.getMatchingFile(11000000, vpid1, 0x400100);
+ assertEquals(expected, matchingFile);
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x400000, "/tmp/bar", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "/tmp/debuglink2", false);
+ matchingFile = fModule.getMatchingFile(12000000, vpid2, 0x400100);
+ assertEquals(expected, matchingFile);
+ }
+
+
+ /**
+ * Test the analysis with a trace with debug_link information.
+ */
+ @Test
+ public void testBuildIDDebugLink() {
+ UstDebugInfoLoadedBinaryFile matchingFile, expected;
+
+ setupTrace(SYNTH_BUILDID_DEBUGLINK_TRACE);
+ executeModule();
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x400000, "/tmp/foo_nn", null, null, false);
+ matchingFile = fModule.getMatchingFile(17000000, 1337, 0x400100);
+ assertEquals(expected, matchingFile);
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x400000, "/tmp/foo_yn", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", null, false);
+ matchingFile = fModule.getMatchingFile(18000000, 1338, 0x400100);
+ assertEquals(expected, matchingFile);
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x400000, "/tmp/foo_ny", null, "/tmp/debug_link1", false);
+ matchingFile = fModule.getMatchingFile(19000000, 1339, 0x400100);
+ assertEquals(expected, matchingFile);
+
+ expected = new UstDebugInfoLoadedBinaryFile(0x400000, "/tmp/foo_yy", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "/tmp/debug_link2", false);
+ matchingFile = fModule.getMatchingFile(20000000, 1340, 0x400100);
+ assertEquals(expected, matchingFile);
}
/**
*/
@Test
public void testGetAllBinaries() {
+ setupTrace(REAL_TEST_TRACE);
executeModule();
+
List<UstDebugInfoBinaryFile> actualBinaries = Lists.newArrayList(fModule.getAllBinaries());
List<UstDebugInfoBinaryFile> expectedBinaries = Lists.newArrayList(
- new UstDebugInfoBinaryFile("/home/alexandre/src/lttng-project/lttng/trace-utils/dynamicLinking/libhello.so", "c9ac43c6b4251b0789ada66931e33487d65f64a6", true),
- new UstDebugInfoBinaryFile("/home/alexandre/src/lttng-project/lttng/trace-utils/dynamicLinking/main.out", "0ec3294d0cacff93ec30b7161ff21efcd4cdd327", false),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/ld-2.23.so", "edfa6d46e00ca97f349fdd3333d88493d442932c", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libc-2.23.so", "369de0e1d833caa693af17f17c83ba937f0a4dad", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libdl-2.23.so", "a2adf3615338d49c702c41eb83a99ab743d2b574", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libgcc_s.so.1", "68220ae2c65d65c1b6aaa12fa6765a6ec2f5f434", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.0", "8b553ecf9133c50f36a7345a4924c5b97e9daa11", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/liblzma.so.5.0.0", "15aed4855920e5a0fb8791b683eb88c7e1199260", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libm-2.23.so", "5c4078c04888a418f3db0868702ecfdb35b3ad8b", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libpcre.so.3.13.2", "390b2228e9a1071bb0be285d77b6669cb37ce628", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libpthread-2.23.so", "b77847cc9cacbca3b5753d0d25a32e5795afe75b", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libresolv-2.23.so", "81ef82040e9877e63adca93b365f52a4bb831ee1", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/librt-2.23.so", "a779dbcb3a477dc0c8d09b60fac7335d396c19df", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libselinux.so.1", "62a57085aa17036efdcecf6655d9e7be566f6948", true),
- new UstDebugInfoBinaryFile("/lib/x86_64-linux-gnu/libz.so.1.2.8", "340b7b463f981b8a0fb3451751f881df1b0c2f74", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/indicator-transfer/indicator-transfer-service", "01c605bcf38d068d77a6e0a02cede6a50c5750b5", false),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/indicator-transfer/libbuteo-transfers.so", "a3a54ba90d7b7b67e0be9baaae3b91675b630a09", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/indicator-transfer/libdmtransfers.so", "ad8ebd563d733818f9f4a399b8d34c1b7e846f3d", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libQt5Core.so.5.5.1", "478d22fbdf6a3e0ec3b499bd2bb8e97dbed84fb6", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libQt5Xml.so.5.5.1", "3a16f2feccfdbca6a40d9bd43ae5a966bca065c7", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libaccounts-glib.so.0.1.3", "3aaeb6f74d07bd2331fa1664a90b11ca5cc1b71e", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libaccounts-qt5.so.1.2.0", "c4c36b5efb4dd5f92a53ed0a2844239f564328d7", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.58.0", "8cebf2501fd917f393ef1390777415fca9289878", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0", "bb484981ddf4152bb6f02ad3a700ec21ca3805e2", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libclick-0.4.so.0.4.0", "79609d999eab77f934f6d7d296074ea54f1410e8", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libffi.so.6.0.4", "9d9c958f1f4894afef6aecd90d1c430ea29ac34f", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libgee-0.8.so.2.5.1", "96aff01de4c5e4817d483de7278c8cc9c6d02001", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.4800.0", "01d955da82f10209b515f362b2352d5a0d0b5330", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.4800.0", "a9190276f6246d3a44ba820510ef7d469ea556b1", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4800.0", "bce3f25958a5b88c9493990daf0c90a787444c28", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libicudata.so.55.1", "233845f0cd27642c4b2cc43979c8801b52bc00a9", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libicui18n.so.55.1", "7bf3774116dbb992ffcc2156b6f5c44f0a328f00", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libicuuc.so.55.1", "323e4878073bb4e0d7b174ae24e383ec5e05d68a", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libindicator-transfer.so.0.0.2", "4e472120f2a19343e1ff5928459edcb4a6c0b1e2", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libjson-glib-1.0.so.0.102.0", "55c87753a67b0c24922bd091f042b9d8bd4995dc", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/liblttng-ust-dl.so.0.0.0", "450c14d5a7a72780b2d88a3cf73d2e12c2774676", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0.0.0", "e70e1748e137bb59b542e15e0722455b998355fc", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/liblttng-ust.so.0.0.0", "101115876419ead3a8bd9a9a08a6d92984015b99", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libmirclient.so.9", "b4c1509382d3ef5f7458db59710b4d30dad86b5d", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libmircommon.so.5", "25b5830854701533323f15195ae9e501ad7f772b", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libmirprotobuf.so.3", "2f6b1a56f1ac43ae001dffde4dc1a24bfee04dec", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libpcre16.so.3.13.2", "2cc13260733c5b35f311725fca88219b338d5390", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libprotobuf-lite.so.9.0.1", "625eb54ba7ccc3af18d3193e22cbe9f23dfb88e5", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6", "d9782ba023caec26b15d8676e3a5d07b55e121ef", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21", "662f4598d7854c6731f13802486e477a7bdb09c7", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libubuntu-app-launch.so.2.0.0", "1e5753f4feda98548bd230eb07b81e330f419463", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/liburcu-bp.so.4.0.0", "d208fcd0e6e6968b8110d9c487f63ae1a400e7c2", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/liburcu-cds.so.4.0.0", "177fbd0a1b21145ad2f29bf41ba9f45e43b1ae4a", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/liburl-dispatcher.so.1.0.0", "58e7febb6e33418eee311c0bad19aace5cba0fd1", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0", "29ebf0cc0837b321e6a751b9b7d43ae9f8f3f0c0", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libxml2.so.2.9.3", "a155c7bc345d0e0b711be09120204bd88f475f9e", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/libzeitgeist-2.0.so.0.0.0", "211049ef6c5ed6e7bbcdc75c0a25d1f11755151d", true),
- new UstDebugInfoBinaryFile("/usr/lib/x86_64-linux-gnu/url-dispatcher/url-dispatcher", "694fcf16ee9241e66a33de671d10f854312e0c87", false));
+ new UstDebugInfoBinaryFile("/home/simark/src/babeltrace/tests/debug-info-data/libhello_so",
+ "cdd98cdd87f7fe64c13b6daad553987eafd40cbb", null, true),
+ new UstDebugInfoBinaryFile("/home/simark/src/babeltrace/tests/debug-info-data/test",
+ "0683255d2cf219c33cc0efd6039db09ccc4416d7", null, false),
+ new UstDebugInfoBinaryFile("[linux-vdso.so.1]", null, null, false),
+ new UstDebugInfoBinaryFile("/usr/local/lib/liblttng-ust-dl.so.0.0.0",
+ "39c035014cc02008d6884fcb1be4e020cc820366", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/libdl-2.23.so",
+ "db3f9be9f4ebe9e2a21e4ae0b4ef7165d40fdfef", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/libc-2.23.so",
+ "946025a5cad7b5f2dfbaebc6ebd1fcc004349b48", null, true),
+ new UstDebugInfoBinaryFile("/usr/local/lib/liblttng-ust.so.0.0.0",
+ "405b0b15daa73eccb88076247ba30356c00d3b92", null, true),
+ new UstDebugInfoBinaryFile("/usr/local/lib/liblttng-ust-tracepoint.so.0.0.0",
+ "62c028aad38adb5e0910c527d522e8c86a0a3344", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/librt-2.23.so",
+ "aba676bda7fb6adb71e100159915504e1a0c17e6", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/liburcu-bp.so.4.0.0",
+ "b9dfadea234107f8453bc636fc160047e0c01b7a", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/liburcu-cds.so.4.0.0",
+ "420527f6dacc762378d9fa7def54d91c80a6c87e", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/libpthread-2.23.so",
+ "d91ed99c8425b7ce5da5bb750662a91038e02a78", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/ld-2.23.so",
+ "524eff0527e923e4adc4be9db1ef7475607b92e8", null, true),
+ new UstDebugInfoBinaryFile("/usr/lib/liburcu-common.so.4.0.0",
+ "f279a6d46a2b846e15e7abd99cfe9fbe8d7f8295", null, true));
Comparator<UstDebugInfoBinaryFile> comparator = Comparator.comparing(UstDebugInfoBinaryFile::getFilePath);
actualBinaries.sort(comparator);
org.eclipse.tracecompass.tmf.ctf.core,
org.eclipse.tracecompass.lttng2.control.core,
org.eclipse.tracecompass.ctf.core
-Import-Package: com.google.common.base,
+Import-Package: com.google.common.annotations;version="15.0.0",
+ com.google.common.base,
com.google.common.cache,
com.google.common.collect,
com.google.common.io
private static class FileOffset {
private final String fFilePath;
- private final String fBuildId;
+ private final @Nullable String fBuildId;
private final long fOffset;
- public FileOffset(String filePath, String buildId, long offset) {
+ public FileOffset(String filePath, @Nullable String buildId, long offset) {
fFilePath = filePath;
fBuildId = buildId;
fOffset = offset;
* @return The list of callsites corresponding to the offset, reported from
* the "highest" inlining location, down to the initial definition.
*/
- public static @Nullable Iterable<SourceCallsite> getCallsiteFromOffset(File file, String buildId, long offset) {
+ public static @Nullable Iterable<SourceCallsite> getCallsiteFromOffset(File file, @Nullable String buildId, long offset) {
if (!Files.exists((file.toPath()))) {
return null;
}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
- *
- * All rights reserved. This program and the accompanying materials are
- * made available under the terms of the Eclipse Public License v1.0 which
- * accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo;
-
-import java.util.Objects;
-
-import org.eclipse.jdt.annotation.Nullable;
-
-/**
- * Wrapper class to reference to a particular binary, which can be an
- * executable or library. It contains both the complete file path (at the
- * time the trace was taken) and the build ID of the binary.
- */
-public class UstDebugInfoBinaryFile implements Comparable<UstDebugInfoBinaryFile> {
-
- private final String fFilePath;
- private final String fBuildId;
- private final boolean fIsPic;
- private final String fToString;
-
- /**
- * Constructor
- *
- * @param filePath
- * The binary's path on the filesystem
- * @param buildId
- * The binary's unique buildID (in base16 form).
- * @param isPic
- * If the binary is position-independent or not
- */
- public UstDebugInfoBinaryFile(String filePath, String buildId, boolean isPic) {
- fFilePath = filePath;
- fBuildId = buildId;
- fIsPic = isPic;
-
- fToString = filePath + " (" + //$NON-NLS-1$
- (fIsPic ? "PIC" : "non-PIC") + //$NON-NLS-1$ //$NON-NLS-2$
- ", " + buildId + ')'; //$NON-NLS-1$
- }
-
- /**
- * Get the file's path, as was referenced to in the trace.
- *
- * @return The file path
- */
- public String getFilePath() {
- return fFilePath;
- }
-
- /**
- * Get the build ID of the binary. It should be a unique identifier.
- *
- * On Unix systems, you can use <pre>eu-readelf -n [binary]</pre> to get
- * this ID.
- *
- * @return The file's build ID.
- */
- public String getBuildId() {
- return fBuildId;
- }
-
- /**
- * Return whether the given file (binary or library) is Position-Independent
- * Code or not.
- *
- * This indicates whether the symbols in the ELF are absolute or relative to
- * the runtime base address, and determines which address we need to pass to
- * 'addr2line'.
- *
- * @return Whether this file is position-independent or not
- */
- public boolean isPic() {
- return fIsPic;
- }
-
- @Override
- public String toString() {
- return fToString;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof UstDebugInfoBinaryFile)) {
- return false;
- }
- UstDebugInfoBinaryFile other = (UstDebugInfoBinaryFile) obj;
- return (fFilePath.equals(other.fFilePath) &&
- fBuildId.equals(other.fBuildId) &&
- fIsPic == other.fIsPic);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(fBuildId, fFilePath, fIsPic);
- }
-
- /**
- * Used for sorting. Sorts by using alphabetical order of the file
- * paths.
- */
- @Override
- public int compareTo(@Nullable UstDebugInfoBinaryFile o) {
- if (o == null) {
- return 1;
- }
- return fFilePath.compareTo(o.fFilePath);
- }
-}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
- *
- * All rights reserved. This program and the accompanying materials are
- * made available under the terms of the Eclipse Public License v1.0 which
- * accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo;
-
-/**
- * Simple extension to {@link UstDebugInfoBinaryFile} that adds the base address at
- * which the given binary or library is loaded.
- *
- * @author Alexandre Montplaisir
- */
-public class UstDebugInfoLoadedBinaryFile extends UstDebugInfoBinaryFile {
-
- private final long baseAddress;
-
- /**
- * Constructor
- *
- * @param baseAddress
- * The base address at which the binary or library is loaded
- * @param filePath
- * The file path of the loaded binary/library
- * @param buildId
- * The build ID of the binary object
- * @param isPic
- * If the binary is position-independent or not
- */
- public UstDebugInfoLoadedBinaryFile(long baseAddress, String filePath, String buildId, boolean isPic) {
- super(filePath, buildId, isPic);
- this.baseAddress = baseAddress;
- }
-
- /**
- * Return the base address at which the object is loaded.
- *
- * @return The base address
- */
- public long getBaseAddress() {
- return baseAddress;
- }
-}
import java.util.HashMap;
import java.util.Map;
+import java.util.logging.Logger;
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.tracecompass.internal.lttng2.ust.core.Activator;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.log.TraceCompassLog;
import org.eclipse.tracecompass.internal.lttng2.ust.core.trace.layout.LttngUst28EventLayout;
import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
import org.eclipse.tracecompass.lttng2.ust.core.trace.layout.ILttngUstEventLayout;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
-import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
+import org.eclipse.tracecompass.tmf.core.util.Pair;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.BaseEncoding;
* The layout of the generated attribute tree will look like this:
*
* <pre>
- * * [root]
- * +-- 1000
- * +-- 2000
- * ...
- * +-- 3000 (VPIDs)
- * +-- baddr (value = addr range end, long)
- * | +-- buildId (value = /path/to/library (sopath), string)
- * | +- is_pic (value = 0 or 1 (int))
- * +-- baddr
- * | +-- buildId1
- * | +- is_pic
- * | +-- buildId2 (if the same address is re-used later)
- * | +- is_pic
- * ...
+ * Key Value
+ * /vpid null
+ * /vpid/<baddr> Integer 1 if the memory mapping active at this
+ * point in time, null otherwise.
+ * /vpid/<baddr>/build_id Build ID of the binary as an hex string, e.g.
+ * "0123456789abcdef", or null if it doesn't have a
+ * build id.
+ * /vpid/<baddr>/debug_link Path to the separate debug info of the binary, e.g.
+ * "/usr/lib/libhello.so.debug", or null if it doesn't
+ * have separate debug info.
+ * /vpid/<baddr>/memsz Size of the memory mapping in bytes.
+ * /vpid/<baddr>/path Path to the binary, e.g. "/usr/lib/libhello.so".
+ * /vpid/<baddr>/is_pic Integer 1 if the binary contains position
+ * independent code, 0 otherwise.
* </pre>
*
- * The "baddr" attribute name will represent the range start as a string, and
- * its value will be range end. If null, it means this particular library is not
- * loaded at this location at the moment.
- *
- * This sits under the mtime (modification time of the file) attribute. This is
- * to handle cases like multiple concurrent dlopen's of the same library, or the
- * very mind-blowing edge case of a file being modified and being reloaded later
- * on, possibly side-by-side with its previous version.
- *
- * Since the state system is not a spatial database, it's not really worth
- * indexing by memory ranges, and since the amount of loaded libraries is
- * usually small, we should afford to iterate through all mappings to find each
- * match.
- *
- * Still, for better scalability (and for science), it could be interesting to
- * look into storing the memory-model-over-time in something like an R-Tree.
+ * The "baddr" attribute name represents the memory mapping base address a
+ * string (in decimal).
*
* @author Alexandre Montplaisir
+ * @author Simon Marchi
*/
public class UstDebugInfoStateProvider extends AbstractTmfStateProvider {
- /**
- * Sub-attribute indicating if a given binary is PIC (position-independent
- * code) or not. This information is present directly in the trace.
- */
- public static final String IS_PIC_ATTRIB = "is_pic"; //$NON-NLS-1$
+ /** State system attribute name for the in-memory binary size */
+ public static final String MEMSZ_ATTRIB = "memsz"; //$NON-NLS-1$
+
+ /** State system attribute name for the binary path */
+ public static final String PATH_ATTRIB = "path"; //$NON-NLS-1$
+
+ /** State system attribute name for the PICness of the binary */
+ public static final String IS_PIC_ATTRIB = "is_pic"; //$NON-NLS-1$
- /* Version of this state provider */
- private static final int VERSION = 2;
+ /** State system attribute name for the build ID of the binary */
+ public static final String BUILD_ID_ATTRIB = "build_id"; //$NON-NLS-1$
+
+ /** State system attribute name for the debug link of the binary */
+ public static final String DEBUG_LINK_ATTRIB = "debug_link"; //$NON-NLS-1$
+
+ /** Version of this state provider */
+ private static final int VERSION = 3;
+
+ private static final Logger LOGGER = TraceCompassLog.getLogger(UstDebugInfoStateProvider.class);
private static final int DL_DLOPEN_INDEX = 1;
private static final int DL_BUILD_ID_INDEX = 2;
private static final int STATEDUMP_BIN_INFO_INDEX = 5;
private static final int STATEDUMP_BUILD_ID_INDEX = 6;
private static final int STATEDUMP_DEBUG_LINK_INDEX = 7;
+ private static final int STATEDUMP_START_INDEX = 8;
private final LttngUst28EventLayout fLayout;
private final Map<String, Integer> fEventNames;
- /**
- * We need both the soinfo/dlopen event AND the matching build_id/debug_link
- * event to get all the information about a particular binary.
- *
- * Between these two events, we will store the <baddr, BinInfo> in here.
+ /*
+ * Store for data that is incomplete, for which we are waiting for some
+ * upcoming events (build_id or debug_link). Maps <vpid, baddr> to
+ * PendingBinInfo object.
*/
- private final Map<Long, BinInfo> fPendingEntries = new HashMap<>();
+ private final Map<Pair<Long, Long>, PendingBinInfo> fPendingBinInfos = new HashMap<>();
- /**
- * Information contained in a "bin_info" event, which means a binary's path,
- * base address, and if it is a PIC or not.
- */
- private static class BinInfo {
- public final long fBaddr;
- public final String fPath;
- public final int fIsPic;
+ private class PendingBinInfo {
+
+ /* The event data, saved here until we put everything in the state system. */
+ private final long fVpid;
+ private final long fBaddr;
+ private final long fMemsz;
+ private final String fPath;
+ private final boolean fIsPIC;
+
+ private @Nullable String fBuildId = null;
+ private @Nullable String fDebugLink = null;
- public BinInfo(long baddr, String path, int isPic) {
+ /* Which info are we waiting for? */
+ private boolean fBuildIdPending;
+ private boolean fDebugLinkPending;
+
+ public PendingBinInfo(boolean hasBuildId, boolean hasDebugLink,
+ long vpid, long baddr, long memsz, String path, boolean isPIC) {
+ fVpid = vpid;
fBaddr = baddr;
+ fMemsz = memsz;
fPath = path;
- fIsPic = isPic;
+ fIsPIC = isPIC;
+
+ fBuildIdPending = hasBuildId;
+ fDebugLinkPending = hasDebugLink;
+ }
+
+ boolean done() {
+ return !(fBuildIdPending || fDebugLinkPending);
+ }
+
+ public void setBuildId(String buildId) {
+ fBuildIdPending = false;
+ fBuildId = buildId;
+ }
+
+ public @Nullable String getBuildId() {
+ return fBuildId;
+ }
+
+ public void setDebugLink(String debugLink) {
+ fDebugLinkPending = false;
+ fDebugLink = debugLink;
+ }
+
+ public @Nullable String getDebugLink() {
+ return fDebugLink;
}
}
builder.put(layout.eventStatedumpBinInfo(), STATEDUMP_BIN_INFO_INDEX);
builder.put(layout.eventStateDumpBuildId(), STATEDUMP_BUILD_ID_INDEX);
builder.put(layout.eventStateDumpDebugLink(), STATEDUMP_DEBUG_LINK_INDEX);
+ builder.put(layout.eventStatedumpStart(), STATEDUMP_START_INDEX);
return builder.build();
}
}
int intIndex = index.intValue();
+ switch (intIndex) {
+ case STATEDUMP_START_INDEX: {
+ handleStatedumpStart(event, vpid, ss);
+ break;
+ }
+
+ case DL_DLOPEN_INDEX:
+ case STATEDUMP_BIN_INFO_INDEX: {
+ handleOpen(event, vpid, ss);
+ break;
+ }
+
+ case DL_BUILD_ID_INDEX:
+ case STATEDUMP_BUILD_ID_INDEX: {
+ handleBuildId(event, vpid, ss);
+ break;
+ }
+
+ case DL_DEBUG_LINK_INDEX:
+ case STATEDUMP_DEBUG_LINK_INDEX: {
+ handleDebugLink(event, vpid, ss);
+ break;
+ }
+
+ case DL_DLCLOSE_INDEX: {
+ handleClose(event, vpid, ss);
+ break;
+ }
+
+ default:
+ /* Ignore other events */
+ break;
+ }
+ }
+
+ /**
+ * Commit the binary information contained in pending to the state system.
+ *
+ * This method should only be called when there is no more pending
+ * information for that binary.
+ */
+ private static void commitPendingToStateSystem(PendingBinInfo pending,
+ long ts, ITmfStateSystemBuilder ss) {
+ if (!pending.done()) {
+ throw new IllegalStateException();
+ }
+
+ long vpid = pending.fVpid;
+ long baddr = pending.fBaddr;
+ long memsz = pending.fMemsz;
+ String path = pending.fPath;
+ String buildId = pending.getBuildId();
+ String debugLink = pending.getDebugLink();
+ boolean isPIC = pending.fIsPIC;
+
+ /* Create the "top-level" attribute for this object. */
+ int baddrQuark = ss.getQuarkAbsoluteAndAdd(Long.toString(vpid), Long.toString(baddr));
+
+ /* Create the attributes that contain actual data. */
+ int memszQuark = ss.getQuarkRelativeAndAdd(baddrQuark, MEMSZ_ATTRIB);
+ int pathQuark = ss.getQuarkRelativeAndAdd(baddrQuark, PATH_ATTRIB);
+ int isPICQuark = ss.getQuarkRelativeAndAdd(baddrQuark, IS_PIC_ATTRIB);
+ int buildIdQuark = ss.getQuarkRelativeAndAdd(baddrQuark, BUILD_ID_ATTRIB);
+ int debugLinkQuark = ss.getQuarkRelativeAndAdd(baddrQuark, DEBUG_LINK_ATTRIB);
try {
- switch (intIndex) {
- case DL_DLOPEN_INDEX:
- case STATEDUMP_BIN_INFO_INDEX:
- {
- handleOpen(event, vpid, ss);
- break;
+ ss.modifyAttribute(ts, TmfStateValue.newValueInt(1), baddrQuark);
+ ss.modifyAttribute(ts, TmfStateValue.newValueLong(memsz), memszQuark);
+ ss.modifyAttribute(ts, TmfStateValue.newValueString(path), pathQuark);
+ ss.modifyAttribute(ts, TmfStateValue.newValueInt(isPIC ? 1 : 0), isPICQuark);
+ if (buildId != null) {
+ ss.modifyAttribute(ts, TmfStateValue.newValueString(buildId), buildIdQuark);
+ } else {
+ ss.modifyAttribute(ts, TmfStateValue.nullValue(), buildIdQuark);
}
- case DL_BUILD_ID_INDEX:
- case STATEDUMP_BUILD_ID_INDEX:
- {
- handleBuildId(event, vpid, ss);
- break;
+ if (debugLink != null) {
+ ss.modifyAttribute(ts, TmfStateValue.newValueString(debugLink), debugLinkQuark);
+ } else {
+ ss.modifyAttribute(ts, TmfStateValue.nullValue(), debugLinkQuark);
}
+ } catch (StateValueTypeException e) {
+ /* Something went very wrong. */
+ throw new IllegalStateException(e);
+ }
+ }
- case DL_DEBUG_LINK_INDEX:
- case STATEDUMP_DEBUG_LINK_INDEX:
- /* Fields: Long baddr, Long crc, String filename */
- {
- // TODO NYI
- break;
- }
+ /**
+ * Locate a PendingBinInfo object in the map of pending binary informations
+ * with the key <vpid, baddr>. Remove it from the map and return it if it is
+ * found, return null otherwise.
+ */
+ private @Nullable PendingBinInfo retrievePendingBinInfo(long vpid, long baddr) {
+ Pair<Long, Long> key = new Pair<>(vpid, baddr);
- case DL_DLCLOSE_INDEX:
- {
- handleClose(event, vpid, ss);
- break;
- }
+ return fPendingBinInfos.remove(key);
+ }
- default:
- /* Ignore other events */
- break;
- }
+ /**
+ * Check whether we know everything there is to know about the binary
+ * described by pending, and if so, commit it to the state system.
+ * Otherwise, put it in the map of pending binary informations.
+ */
+ private void processPendingBinInfo(PendingBinInfo pending, long ts,
+ ITmfStateSystemBuilder ss) {
+ if (pending.done()) {
+ commitPendingToStateSystem(pending, ts, ss);
+ } else {
+ /* We are expecting more data for this binary, put in the pending map. */
+ Pair<Long, Long> key = new Pair<>(pending.fVpid, pending.fBaddr);
+
+ fPendingBinInfos.put(key, pending);
+ }
+ }
+
+ /**
+ * Handle the start of a statedump.
+ *
+ * When a process does an exec, a new statedump is done and all previous
+ * mappings are now invalid.
+ */
+ private static void handleStatedumpStart(ITmfEvent event, final Long vpid, final ITmfStateSystemBuilder ss) {
+ try {
+ long ts = event.getTimestamp().getValue();
+ int vpidQuark = ss.getQuarkAbsolute(vpid.toString());
+
+ ss.removeAttribute(ts, vpidQuark);
} catch (AttributeNotFoundException e) {
- Activator.getDefault().logError("Unexpected exception in UstDebugInfoStateProvider", e); //$NON-NLS-1$
+ /* We didn't know anything about this vpid yet, so there is nothing to remove. */
}
}
/**
* Handle opening a shared library.
*
- * Uses fields: Long baddr, Long memsz, String sopath
+ * Uses fields: Long baddr, Long memsz, String path, Long is_pic
*/
private void handleOpen(ITmfEvent event, final Long vpid, final ITmfStateSystemBuilder ss) {
- Long baddr = (Long) event.getContent().getField(fLayout.fieldBaddr()).getValue();
- Long memsz = (Long) event.getContent().getField(fLayout.fieldMemsz()).getValue();
- String sopath = (String) event.getContent().getField(fLayout.fieldPath()).getValue();
+ Long baddr = event.getContent().getFieldValue(Long.class, fLayout.fieldBaddr());
+ Long memsz = event.getContent().getFieldValue(Long.class, fLayout.fieldMemsz());
+ String path = event.getContent().getFieldValue(String.class, fLayout.fieldPath());
+ Long hasBuildIdValue = event.getContent().getFieldValue(Long.class, fLayout.fieldHasBuildId());
+ Long hasDebugLinkValue = event.getContent().getFieldValue(Long.class, fLayout.fieldHasDebugLink());
+ Long isPicValue = event.getContent().getFieldValue(Long.class, fLayout.fieldIsPic());
+
+ if (baddr == null ||
+ memsz == null ||
+ path == null ||
+ hasBuildIdValue == null ||
+ hasDebugLinkValue == null) {
+ LOGGER.warning(() -> "[UstDebugInfoStateProvider:InvalidDlOpenEvent] event=" + event.toString()); //$NON-NLS-1$
+ return;
+ }
- /* "dlopen" events do not have a "is_pic" field, they always refer to PIC libs */
- ITmfEventField isPicField = event.getContent().getField(fLayout.fieldIsPic());
- Long isPicVal = (isPicField == null ? 1L : (Long) isPicField.getValue());
+ /*
+ * The is_pic field is only present in the lttng_ust_statedump:bin_info
+ * event. Binaries loaded with dlopen always have PIC. Therefore, we
+ * start assuming isPIC is true, and change our mind if the field is
+ * present and says the opposite.
+ */
+ boolean isPic = true;
+ if (isPicValue != null) {
+ isPic = (isPicValue != 0);
+ }
- long endAddr = baddr.longValue() + memsz.longValue();
- int addrQuark = ss.getQuarkAbsoluteAndAdd(vpid.toString(), baddr.toString());
+ boolean hasBuildId = hasBuildIdValue != 0;
+ boolean hasDebugLink = hasDebugLinkValue != 0;
long ts = event.getTimestamp().getValue();
- ss.modifyAttribute(ts, TmfStateValue.newValueLong(endAddr), addrQuark);
- /*
- * Add this library to the pending entries, the matching
- * build_id/debug_link event will finish updating this attribute
- */
- BinInfo binInfo = new BinInfo(baddr, checkNotNull(sopath), isPicVal.intValue());
- fPendingEntries.put(binInfo.fBaddr, binInfo);
+ PendingBinInfo p = new PendingBinInfo(hasBuildId, hasDebugLink, vpid, baddr, memsz, path, isPic);
+
+ processPendingBinInfo(p, ts, ss);
}
/**
*
* Uses fields: Long baddr, long[] build_id
*/
- private void handleBuildId(ITmfEvent event, final Long vpid, final ITmfStateSystemBuilder ss) throws AttributeNotFoundException {
- Long baddr = (Long) event.getContent().getField(fLayout.fieldBaddr()).getValue();
- long[] buildIdArray = checkNotNull((long[]) event.getContent().getField(fLayout.fieldBuildId()).getValue());
+ private void handleBuildId(ITmfEvent event, final Long vpid, final ITmfStateSystemBuilder ss) {
+ long[] buildIdArray = event.getContent().getFieldValue(long[].class, fLayout.fieldBuildId());
+ Long baddr = event.getContent().getFieldValue(Long.class, fLayout.fieldBaddr());
+
+ if (buildIdArray == null || baddr == null) {
+ LOGGER.warning(() -> "[UstDebugInfoStateProvider:InvalidBuildIdEvent] event=" + event.toString()); //$NON-NLS-1$
+ return;
+ }
+
/*
* Decode the buildID from the byte array in the trace field.
* Use lower-case encoding, since this is how eu-readelf
* displays it.
*/
- String buildId = BaseEncoding.base16().encode(longArrayToByteArray(buildIdArray)).toLowerCase();
+ String buildId = checkNotNull(BaseEncoding.base16().encode(longArrayToByteArray(buildIdArray)).toLowerCase());
- /* Retrieve the matching sopath from the pending entries */
- BinInfo binInfo = fPendingEntries.remove(baddr);
- if (binInfo == null) {
- /*
- * We did not previously handle the initial event for this
- * library. Lost events?
- */
- Activator.getDefault().logWarning("UstDebugInfoStateProvider: Received a build_id event without a matching soinfo/dlopen one."); //$NON-NLS-1$
+ long ts = event.getTimestamp().getValue();
+
+ PendingBinInfo p = retrievePendingBinInfo(vpid, baddr);
+
+ /*
+ * We have never seen the bin_info event this event is related to,
+ * there's nothing much we can do.
+ */
+ if (p == null) {
+ return;
+ }
+
+ p.setBuildId(buildId);
+
+ processPendingBinInfo(p, ts, ss);
+ }
+
+ private void handleDebugLink(ITmfEvent event, final Long vpid, final ITmfStateSystemBuilder ss) {
+ Long baddr = event.getContent().getFieldValue(Long.class, fLayout.fieldBaddr());
+ String debugLink = event.getContent().getFieldValue(String.class, fLayout.fieldDebugLinkFilename());
+
+ if (baddr == null || debugLink == null) {
+ LOGGER.warning(() -> "[UstDebugInfoStateProvider:InvalidDebugLinkEvent] event=" + event.toString()); //$NON-NLS-1$
return;
}
- /* addrQuark should already exist */
- int addrQuark = ss.getQuarkAbsolute(vpid.toString(), baddr.toString());
- /* build-id attribute */
- int buildIdQuark = ss.getQuarkRelativeAndAdd(addrQuark, buildId);
long ts = event.getTimestamp().getValue();
- ss.modifyAttribute(ts, TmfStateValue.newValueString(binInfo.fPath), buildIdQuark);
- /* "is_pic" sub-attribute */
- int isPicQuark = ss.getQuarkRelativeAndAdd(buildIdQuark, IS_PIC_ATTRIB);
- ss.modifyAttribute(ts, TmfStateValue.newValueInt(binInfo.fIsPic), isPicQuark);
+ PendingBinInfo pendingBinInfo = retrievePendingBinInfo(vpid, baddr);
+ if (pendingBinInfo == null) {
+ return;
+ }
+
+ pendingBinInfo.setDebugLink(debugLink);
+ processPendingBinInfo(pendingBinInfo, ts, ss);
}
/**
* Uses fields: Long baddr
*/
private void handleClose(ITmfEvent event, final Long vpid, final ITmfStateSystemBuilder ss) {
- Long baddr = (Long) event.getContent().getField(fLayout.fieldBaddr()).getValue();
+ Long baddr = event.getContent().getFieldValue(Long.class, fLayout.fieldBaddr());
+
+ if (baddr == null) {
+ LOGGER.warning(() -> "[UstDebugInfoStateProvider:InvalidDlCloseEvent] event=" + event.toString()); //$NON-NLS-1$
+ return;
+ }
try {
int quark = ss.getQuarkAbsolute(vpid.toString(), baddr.toString());
public int getVersion() {
return VERSION;
}
-
}
return "path";
}
+ public String fieldHasBuildId() {
+ return "has_build_id";
+ }
+
+ public String fieldHasDebugLink() {
+ return "has_debug_link";
+ }
+
public String fieldBuildId() {
return "build_id";
}
+ public String fieldDebugLinkFilename() {
+ return "filename";
+ }
+
public String fieldIsPic() {
return "is_pic";
}
package org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo;
+import org.eclipse.jdt.annotation.Nullable;
+
/**
* Object carrying the information about the "binary callsite" corresponding to
* an instruction pointer. This consists in:
public class BinaryCallsite {
private final String fBinaryFilePath;
- private final String fBuildId;
+ private final @Nullable String fBuildId;
private final long fOffset;
private final boolean fIsPic;
* absolute address (if isPic is false), or if it is an offset in
* the binary (is isPic is true).
*/
- public BinaryCallsite(String binaryFilePath, String buildId, long offset, boolean isPic) {
+ public BinaryCallsite(String binaryFilePath, @Nullable String buildId, long offset, boolean isPic) {
if (offset < 0) {
throw new IllegalArgumentException("Address offset cannot be negative"); //$NON-NLS-1$
}
*
* @return The build-id
*/
- public String getBuildId() {
+ public @Nullable String getBuildId() {
return fBuildId;
}
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.NavigableSet;
-import java.util.Optional;
+import java.util.OptionalLong;
import java.util.Set;
import java.util.TreeSet;
-import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoBinaryFile;
-import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoLoadedBinaryFile;
import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoStateProvider;
import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.ctf.core.trace.CtfUtils;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
/**
return Collections.EMPTY_SET;
}
- Set<UstDebugInfoBinaryFile> files = new TreeSet<>();
+ final @NonNull Set<UstDebugInfoBinaryFile> files = new TreeSet<>();
ImmutableList.Builder<Integer> builder = ImmutableList.builder();
- List<Integer> vpidQuarks = ss.getSubAttributes(-1, false);
+ List<Integer> vpidQuarks = ss.getSubAttributes(ITmfStateSystem.ROOT_ATTRIBUTE, false);
for (Integer vpidQuark : vpidQuarks) {
builder.addAll(ss.getSubAttributes(vpidQuark, false));
}
List<Integer> baddrQuarks = builder.build();
- /*
- * For each "baddr" attribute, get the "buildId" sub-attribute,
- * whose value is the file path.
- */
-
- for (Integer baddrQuark : baddrQuarks) {
-
- List<Integer> buildIdQuarks = ss.getSubAttributes(baddrQuark, false);
- for (Integer buildIdQuark : buildIdQuarks) {
- String buildId = ss.getAttributeName(buildIdQuark);
+ try {
+ for (Integer baddrQuark : baddrQuarks) {
+ int buildIdQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.BUILD_ID_ATTRIB);
+ int debugLinkQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.DEBUG_LINK_ATTRIB);
+ int pathQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.PATH_ATTRIB);
+ int isPICQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.IS_PIC_ATTRIB);
+ long ts = ss.getStartTime();
/*
- * Explore the history of this attribute "horizontally",
- * even though there should only be one valid interval.
+ * Iterate over each mapping there ever was at this base
+ * address.
*/
- ITmfStateInterval interval = StateSystemUtils.queryUntilNonNullValue(ss, buildIdQuark, ss.getStartTime(), Long.MAX_VALUE);
- if (interval == null) {
- /*
- * If we created the attribute, we should have assigned
- * a value to it!
- */
- throw new IllegalStateException();
- }
- String filePath = interval.getStateValue().unboxStr();
+ ITmfStateInterval interval = StateSystemUtils.queryUntilNonNullValue(ss, baddrQuark, ts, Long.MAX_VALUE);
+ while (interval != null) {
+ ts = interval.getStartTime();
+
+ ITmfStateValue filePathStateValue = ss.querySingleState(ts, pathQuark).getStateValue();
+ String filePath = filePathStateValue.unboxStr();
+
+ ITmfStateValue buildIdStateValue = ss.querySingleState(ts, buildIdQuark).getStateValue();
+ String buildId = unboxStrOrNull(buildIdStateValue);
- /* Retrieve the value of "is_pic" at that time */
- try {
- int isPicQuark = ss.getQuarkRelative(buildIdQuark, UstDebugInfoStateProvider.IS_PIC_ATTRIB);
- int isPicVal = ss.querySingleState(interval.getStartTime(), isPicQuark).getStateValue().unboxInt();
- boolean isPic = (isPicVal != 0);
+ ITmfStateValue debuglinkStateValue = ss.querySingleState(ts, debugLinkQuark).getStateValue();
+ String debugLink = unboxStrOrNull(debuglinkStateValue);
- files.add(new UstDebugInfoBinaryFile(filePath, buildId, isPic));
+ ITmfStateValue isPICStateValue = ss.querySingleState(ts, isPICQuark).getStateValue();
+ Boolean isPIC = isPICStateValue.unboxInt() != 0;
- } catch (AttributeNotFoundException e) {
- /* We should have built "is_pic" sub-attributes */
- throw new IllegalStateException("Missing expected \"is_pic\" attribute"); //$NON-NLS-1$
- } catch (StateSystemDisposedException e) {
- /* We're closing down, ignore */
+ files.add(new UstDebugInfoBinaryFile(filePath, buildId, debugLink, isPIC));
+
+ /*
+ * Go one past the end of the interval, and perform the
+ * query again to find the next mapping at this address.
+ */
+ ts = interval.getEndTime() + 1;
+ interval = StateSystemUtils.queryUntilNonNullValue(ss, baddrQuark, ts, Long.MAX_VALUE);
}
}
+ } catch (AttributeNotFoundException e) {
+ throw new IllegalStateException(e);
+ } catch (StateSystemDisposedException e) {
+ /* Oh well, such is life. */
}
return files;
}
* @param ip
* The instruction pointer of the trace event. Normally comes
* from a 'ip' context.
- * @return The {@link UstDebugInfoBinaryFile} object, containing both the binary's path
- * and its build ID.
+ * @return A {@link UstDebugInfoLoadedBinaryFile} object, describing the
+ * binary file and its base address.
+ * @noreference Meant to be used internally by
+ * {@link UstDebugInfoBinaryAspect} only.
*/
- @Nullable UstDebugInfoLoadedBinaryFile getMatchingFile(long ts, long vpid, long ip) {
- waitForCompletion();
- final ITmfStateSystem ss = getStateSystem();
- if (ss == null) {
- /* State system might not yet be initialized */
- return null;
- }
-
- List<Integer> possibleBaddrQuarks = ss.getQuarks(String.valueOf(vpid), "*"); //$NON-NLS-1$
-
- /* Get the most probable base address from all the known ones */
- NavigableSet<Long> possibleBaddrs = possibleBaddrQuarks.stream()
- .map(quark -> {
- String baddrStr = ss.getAttributeName(quark.intValue());
- return checkNotNull(Long.valueOf(baddrStr));
- })
- .collect(Collectors.toCollection(TreeSet::new));
+ @VisibleForTesting
+ public @Nullable UstDebugInfoLoadedBinaryFile getMatchingFile(long ts, long vpid, long ip) {
+ try {
+ waitForCompletion();
+ final ITmfStateSystem ss = getStateSystem();
+ if (ss == null) {
+ /* State system might not yet be initialized */
+ return null;
+ }
- final Long potentialBaddr = possibleBaddrs.floor(ip);
- if (potentialBaddr == null) {
- return null;
- }
+ List<Integer> possibleBaddrQuarks = ss.getQuarks(String.valueOf(vpid), "*"); //$NON-NLS-1$
+ List<ITmfStateInterval> state = ss.queryFullState(ts);
+
+ /* Get the most probable base address from all the known ones */
+ OptionalLong potentialBaddr = possibleBaddrQuarks.stream()
+ .filter(quark -> {
+ /* Keep only currently (at ts) mapped objects. */
+ ITmfStateValue value = state.get(quark).getStateValue();
+ return value.getType() == ITmfStateValue.Type.INTEGER && value.unboxInt() == 1;
+ })
+ .map(quark -> ss.getAttributeName(quark.intValue()))
+ .mapToLong(baddrStr -> Long.parseLong(baddrStr))
+ .filter(baddr -> baddr <= ip)
+ .max();
+
+ if (!potentialBaddr.isPresent()) {
+ return null;
+ }
- /* Make sure the 'ip' fits in the expected memory range */
- try {
- final List<ITmfStateInterval> fullState = ss.queryFullState(ts);
+ long baddr = potentialBaddr.getAsLong();
+ final int baddrQuark = ss.getQuarkAbsolute(String.valueOf(vpid),
+ String.valueOf(baddr));
- final int baddrQuark = ss.getQuarkAbsolute(String.valueOf(vpid), String.valueOf(potentialBaddr));
- final long endAddr = fullState.get(baddrQuark).getStateValue().unboxLong();
+ final int memszQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.MEMSZ_ATTRIB);
+ final long memsz = state.get(memszQuark).getStateValue().unboxLong();
- if (!(ip < endAddr)) {
+ /* Make sure the 'ip' fits the range of this object. */
+ if (!(ip < baddr + memsz)) {
/*
* Not the correct memory range after all. We do not have
* information about the library that was loaded here.
return null;
}
- /*
- * We've found the correct base address, now to determine what
- * library was loaded there at that time.
- */
- List<Integer> buildIds = ss.getSubAttributes(baddrQuark, false);
- Optional<Integer> potentialBuildIdQuark = buildIds.stream()
- .filter(id -> {
- int quark = id.intValue();
- ITmfStateValue value = fullState.get(quark).getStateValue();
- return (!value.isNull());
- })
- .findFirst();
-
- if (!potentialBuildIdQuark.isPresent()) {
- /* We didn't have the information after all. */
- return null;
- }
+ final int pathQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.PATH_ATTRIB);
+ String filePath = state.get(pathQuark).getStateValue().unboxStr();
- /* Ok, we have everything we need! Return the information. */
- long baddr = Long.parseLong(ss.getAttributeName(baddrQuark));
+ final int buildIdQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.BUILD_ID_ATTRIB);
+ ITmfStateValue buildIdValue = state.get(buildIdQuark).getStateValue();
+ String buildId = unboxStrOrNull(buildIdValue);
- int buildIdQuark = potentialBuildIdQuark.get().intValue();
- String buildId = ss.getAttributeName(buildIdQuark);
- String filePath = fullState.get(buildIdQuark).getStateValue().unboxStr();
+ final int debugLinkQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.DEBUG_LINK_ATTRIB);
+ ITmfStateValue debugLinkValue = state.get(debugLinkQuark).getStateValue();
+ String debugLink = unboxStrOrNull(debugLinkValue);
- int isPicQuark = ss.getQuarkRelative(buildIdQuark, UstDebugInfoStateProvider.IS_PIC_ATTRIB);
- int isPicVal = fullState.get(isPicQuark).getStateValue().unboxInt();
- boolean isPic = (isPicVal != 0);
+ final int isPicQuark = ss.getQuarkRelative(baddrQuark, UstDebugInfoStateProvider.IS_PIC_ATTRIB);
+ boolean isPic = state.get(isPicQuark).getStateValue().unboxInt() != 0;
- return new UstDebugInfoLoadedBinaryFile(baddr, filePath, buildId, isPic);
+ return new UstDebugInfoLoadedBinaryFile(baddr, filePath, buildId, debugLink, isPic);
} catch (AttributeNotFoundException e) {
+ // TODO: that's probably not true anymore
/* We're only using quarks we've checked for. */
throw new IllegalStateException(e);
} catch (StateSystemDisposedException e) {
return null;
}
+ }
+ private static @Nullable String unboxStrOrNull(ITmfStateValue value) {
+ return (value.isNull() ? null : value.unboxStr());
}
}
import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo.UstDebugInfoLoadedBinaryFile;
import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
import org.eclipse.tracecompass.lttng2.ust.core.trace.layout.ILttngUstEventLayout;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
long offset;
if (file.isPic()) {
- offset = (ip - file.getBaseAddress());
+ offset = ip - file.getBaseAddress();
} else {
/*
- * In the case of the object being non-position-independant (loaded
- * at a very low address), we must pass the actual 'ip' address
- * directly to addr2line.
+ * In the case of the object being non-position-independent, we
+ * must pass the actual 'ip' address directly to addr2line.
*/
offset = ip;
}
return new BinaryCallsite(fullPath, file.getBuildId(), offset, file.isPic());
}
-
}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo;
+
+import java.util.Objects;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Wrapper class to reference to a particular binary, which can be an
+ * executable or library. It contains both the complete file path (at the
+ * time the trace was taken) and the build ID of the binary.
+ *
+ * @author Alexandre Montplaisir
+ * @noreference Meant to be used internally by the analysis only
+ */
+public class UstDebugInfoBinaryFile implements Comparable<UstDebugInfoBinaryFile> {
+
+ private final String fFilePath;
+ private final @Nullable String fBuildId;
+ private final @Nullable String fDebugLink;
+ private final boolean fIsPic;
+
+ /**
+ * Constructor
+ *
+ * @param filePath
+ * The binary's path on the filesystem.
+ * @param buildId
+ * The binary's unique buildID (in base16 form).
+ * @param debugLink
+ * Path to the binary's separate debug info.
+ * @param isPic
+ * Whether the code in the binary is position-independent.
+ */
+ public UstDebugInfoBinaryFile(String filePath, @Nullable String buildId,
+ @Nullable String debugLink, boolean isPic) {
+ fFilePath = filePath;
+ fBuildId = buildId;
+ fDebugLink = debugLink;
+ fIsPic = isPic;
+ }
+
+ /**
+ * Get the file's path, as was referenced to in the trace.
+ *
+ * @return The file path
+ */
+ public String getFilePath() {
+ return fFilePath;
+ }
+
+ /**
+ * Get the build ID of the binary. It should be a unique identifier.
+ *
+ * On Unix systems, you can use <pre>eu-readelf -n [binary]</pre> to get
+ * this ID.
+ *
+ * @return The file's build ID, or null if the file has no build ID..
+ */
+ public @Nullable String getBuildId() {
+ return fBuildId;
+ }
+
+ /**
+ * Get the path to the separate debug info of this binary.
+ *
+ * @return The path to the separate debug info, or null if the file has no
+ * separate debug info.
+ */
+ public @Nullable String getDebugLink() {
+ return fDebugLink;
+ }
+
+ /**
+ * Return whether the given file (binary or library) is Position-Independent
+ * Code or not.
+ *
+ * This indicates whether the symbols in the ELF are absolute or relative to
+ * the runtime base address, and determines which address we need to pass to
+ * 'addr2line'.
+ *
+ * @return Whether this file is position-independent or not
+ */
+ public boolean isPic() {
+ return fIsPic;
+ }
+
+ @Override
+ public String toString() {
+ return com.google.common.base.Objects.toStringHelper(this)
+ .add("path", fFilePath)
+ .add("build_id", fBuildId)
+ .add("debug_link", fDebugLink)
+ .add("is_pic", fIsPic)
+ .toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fFilePath, fBuildId, fDebugLink, fIsPic);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(getClass().equals(obj.getClass()))) {
+ return false;
+ }
+
+ UstDebugInfoBinaryFile other = (UstDebugInfoBinaryFile) obj;
+
+ return Objects.equals(fFilePath, other.fFilePath) &&
+ Objects.equals(fBuildId, other.fBuildId) &&
+ Objects.equals(fDebugLink, other.fDebugLink) &&
+ fIsPic == other.fIsPic;
+ }
+
+ /**
+ * Used for sorting. Sorts by using alphabetical order of the file
+ * paths.
+ */
+ @Override
+ public int compareTo(@Nullable UstDebugInfoBinaryFile o) {
+ if (o == null) {
+ return 1;
+ }
+ return fFilePath.compareTo(o.fFilePath);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.lttng2.ust.core.analysis.debuginfo;
+
+import java.util.Objects;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Simple extension to {@link UstDebugInfoBinaryFile} that adds the base address at
+ * which the given binary or library is loaded.
+ *
+ * @author Alexandre Montplaisir
+ * @noreference Meant to be used internally by the analysis only
+ */
+public class UstDebugInfoLoadedBinaryFile extends UstDebugInfoBinaryFile {
+
+ private final long fBaseAddress;
+
+ /**
+ * Constructor
+ *
+ * @param baseAddress
+ * The base address at which the binary or library is loaded
+ * @param filePath
+ * The binary's path on the filesystem.
+ * @param buildId
+ * The binary's unique buildID (in base16 form).
+ * @param debugLink
+ * Path to the binary's separate debug info.
+ * @param isPic
+ * Whether the code in the binary is position-independent.
+ */
+ public UstDebugInfoLoadedBinaryFile(long baseAddress, String filePath,
+ @Nullable String buildId, @Nullable String debugLink,
+ boolean isPic) {
+ super(filePath, buildId, debugLink, isPic);
+ this.fBaseAddress = baseAddress;
+ }
+
+ /**
+ * Return the base address at which the object is loaded.
+ *
+ * @return The base address
+ */
+ public long getBaseAddress() {
+ return fBaseAddress;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), fBaseAddress);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(getClass().equals(obj.getClass()))) {
+ return false;
+ }
+
+ if (!super.equals(obj)) {
+ return false;
+ }
+
+ UstDebugInfoLoadedBinaryFile other = (UstDebugInfoLoadedBinaryFile) obj;
+
+ return Objects.equals(fBaseAddress, other.fBaseAddress);
+ }
+}