1 /*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
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 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.lttng2
.ust
.core
.analysis
.debuginfo
;
12 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
14 import java
.io
.BufferedReader
;
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
;
24 import org
.eclipse
.jdt
.annotation
.Nullable
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.event
.lookup
.TmfCallsite
;
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}.
31 * @author Alexandre Montplaisir
33 public final class FileOffsetMapper
{
35 private static final String ADDR2LINE_EXECUTABLE
= "addr2line"; //$NON-NLS-1$
37 private FileOffsetMapper() {}
40 * Generate the callsites from a given binary file and address offset.
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
47 * The binary file to look at
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.
53 public static @Nullable Iterable
<TmfCallsite
> getCallsiteFromOffset(File file
, long offset
) {
54 if (!Files
.exists((file
.toPath()))) {
57 return getCallsiteFromOffsetWithAddr2line(file
, offset
);
60 private static @Nullable Iterable
<TmfCallsite
> getCallsiteFromOffsetWithAddr2line(File file
, long offset
) {
61 List
<TmfCallsite
> callsites
= new LinkedList
<>();
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$
68 /* Command returned an error */
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$
78 long lineNumber
= Long
.parseLong(elems
[1]);
80 callsites
.add(new TmfCallsite(fileName
, null, lineNumber
));
86 private static @Nullable List
<String
> getOutputFromCommand(List
<String
> command
) {
88 ProcessBuilder builder
= new ProcessBuilder(command
);
89 builder
.redirectErrorStream(true);
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());
96 return (ret
== 0 ? lines
: null);
98 } catch (IOException
| InterruptedException e
) {