lttng.ust: Retrieve the function name when calling addr2line
[deliverable/tracecompass.git] / lttng / org.eclipse.tracecompass.lttng2.ust.core / src / org / eclipse / tracecompass / internal / lttng2 / ust / core / analysis / debuginfo / FileOffsetMapper.java
CommitLineData
522dff53
AM
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
10package org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo;
11
522dff53
AM
12import java.io.BufferedReader;
13import java.io.File;
14import java.io.IOException;
15import java.io.InputStreamReader;
16import java.nio.file.Files;
17import java.util.Arrays;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.stream.Collectors;
21
22import org.eclipse.jdt.annotation.Nullable;
23import org.eclipse.tracecompass.tmf.core.event.lookup.TmfCallsite;
24
25/**
26 * Utility class to get file name, function/symbol name and line number from a
27 * given offset. In TMF this is represented as a {@link TmfCallsite}.
28 *
29 * @author Alexandre Montplaisir
30 */
31public final class FileOffsetMapper {
32
23a8deea 33 private static final String DISCRIMINATOR = "\\(discriminator.*\\)"; //$NON-NLS-1$
522dff53
AM
34 private static final String ADDR2LINE_EXECUTABLE = "addr2line"; //$NON-NLS-1$
35
36 private FileOffsetMapper() {}
37
38 /**
39 * Generate the callsites from a given binary file and address offset.
40 *
41 * Due to function inlining, it is possible for one offset to actually have
42 * multiple call sites. This is why we can return more than one callsite per
43 * call.
44 *
45 * @param file
46 * The binary file to look at
47 * @param offset
48 * The memory offset in the file
49 * @return The list of callsites corresponding to the offset, reported from
50 * the "highest" inlining location, down to the initial definition.
51 */
52 public static @Nullable Iterable<TmfCallsite> getCallsiteFromOffset(File file, long offset) {
53 if (!Files.exists((file.toPath()))) {
11f39f99 54 return null;
522dff53
AM
55 }
56 return getCallsiteFromOffsetWithAddr2line(file, offset);
57 }
58
59 private static @Nullable Iterable<TmfCallsite> getCallsiteFromOffsetWithAddr2line(File file, long offset) {
60 List<TmfCallsite> callsites = new LinkedList<>();
61
38c5f989 62 // FIXME Could eventually use CDT's Addr2line class once it implements --inlines
0e4f957e 63 List<String> output = getOutputFromCommand(Arrays.asList(
38c5f989 64 ADDR2LINE_EXECUTABLE, "-i", "-f", "-C", "-e", file.toString(), "0x" + Long.toHexString(offset))); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
522dff53
AM
65
66 if (output == null) {
67 /* Command returned an error */
68 return null;
69 }
70
38c5f989
AM
71 /*
72 * When passing the -f flag, the output alternates between function
73 * names and file/line location.
74 */
75 boolean oddLine = true;
76 String currentFunctionName = null;
522dff53 77 for (String outputLine : output) {
91fdda3e
MAL
78 // Remove discriminator part, for example: /build/buildd/glibc-2.21/elf/dl-object.c:78 (discriminator 8)
79 outputLine = outputLine.replaceFirst(DISCRIMINATOR, "").trim(); //$NON-NLS-1$
80
38c5f989
AM
81 if (oddLine) {
82 /* This is a line indicating the function name */
83 currentFunctionName = outputLine;
84 } else {
85 /* This is a line indicating a call site */
86 String[] elems = outputLine.split(":"); //$NON-NLS-1$
87 String fileName = elems[0];
88 if (fileName.equals("??")) { //$NON-NLS-1$
89 continue;
90 }
91 long lineNumber = Long.parseLong(elems[1]);
92
93 callsites.add(new TmfCallsite(fileName, currentFunctionName, lineNumber));
522dff53 94 }
522dff53 95
38c5f989
AM
96 /* Flip the boolean for the following line */
97 oddLine = !oddLine;
522dff53
AM
98 }
99
100 return callsites;
101 }
102
103 private static @Nullable List<String> getOutputFromCommand(List<String> command) {
104 try {
105 ProcessBuilder builder = new ProcessBuilder(command);
106 builder.redirectErrorStream(true);
107
108 Process p = builder.start();
a6c5c267
MK
109 try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));) {
110 int ret = p.waitFor();
111 List<String> lines = br.lines().collect(Collectors.toList());
522dff53 112
a6c5c267
MK
113 return (ret == 0 ? lines : null);
114 }
522dff53
AM
115 } catch (IOException | InterruptedException e) {
116 return null;
117 }
118 }
119}
This page took 0.036629 seconds and 5 git commands to generate.