lttng: Do not throw exception if callsite binary is missing
[deliverable/tracecompass.git] / lttng / org.eclipse.tracecompass.lttng2.ust.core / src / org / eclipse / tracecompass / internal / lttng2 / ust / core / analysis / debuginfo / FileOffsetMapper.java
1 /*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
3 *
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 *******************************************************************************/
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.io.BufferedReader;
15 import java.io.File;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.nio.file.Files;
19 import java.util.Arrays;
20 import java.util.LinkedList;
21 import java.util.List;
22 import java.util.stream.Collectors;
23
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.eclipse.tracecompass.tmf.core.event.lookup.TmfCallsite;
26
27 /**
28 * Utility class to get file name, function/symbol name and line number from a
29 * given offset. In TMF this is represented as a {@link TmfCallsite}.
30 *
31 * @author Alexandre Montplaisir
32 */
33 public final class FileOffsetMapper {
34
35 private static final String ADDR2LINE_EXECUTABLE = "addr2line"; //$NON-NLS-1$
36
37 private FileOffsetMapper() {}
38
39 /**
40 * Generate the callsites from a given binary file and address offset.
41 *
42 * Due to function inlining, it is possible for one offset to actually have
43 * multiple call sites. This is why we can return more than one callsite per
44 * call.
45 *
46 * @param file
47 * The binary file to look at
48 * @param offset
49 * The memory offset in the file
50 * @return The list of callsites corresponding to the offset, reported from
51 * the "highest" inlining location, down to the initial definition.
52 */
53 public static @Nullable Iterable<TmfCallsite> getCallsiteFromOffset(File file, long offset) {
54 if (!Files.exists((file.toPath()))) {
55 return null;
56 }
57 return getCallsiteFromOffsetWithAddr2line(file, offset);
58 }
59
60 private static @Nullable Iterable<TmfCallsite> getCallsiteFromOffsetWithAddr2line(File file, long offset) {
61 List<TmfCallsite> callsites = new LinkedList<>();
62
63 // FIXME Could eventually use CDT's Addr2line class once it imlements --inlines
64 List<String> output = getOutputFromCommand(checkNotNull(Arrays.asList(
65 ADDR2LINE_EXECUTABLE, "-i", "-e", file.toString(), "0x" + Long.toHexString(offset)))); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
66
67 if (output == null) {
68 /* Command returned an error */
69 return null;
70 }
71
72 for (String outputLine : output) {
73 String[] elems = outputLine.split(":"); //$NON-NLS-1$
74 String fileName = elems[0];
75 if (fileName.equals("??")) { //$NON-NLS-1$
76 continue;
77 }
78 long lineNumber = Long.parseLong(elems[1]);
79
80 callsites.add(new TmfCallsite(fileName, null, lineNumber));
81 }
82
83 return callsites;
84 }
85
86 private static @Nullable List<String> getOutputFromCommand(List<String> command) {
87 try {
88 ProcessBuilder builder = new ProcessBuilder(command);
89 builder.redirectErrorStream(true);
90
91 Process p = builder.start();
92 BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
93 int ret = p.waitFor();
94 List<String> lines = br.lines().collect(Collectors.toList());
95
96 return (ret == 0 ? lines : null);
97
98 } catch (IOException | InterruptedException e) {
99 return null;
100 }
101 }
102 }
This page took 0.043241 seconds and 6 git commands to generate.