tmf: Move FunctionNameMapper (for the Callstack View) to the core plugin
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / internal / tmf / core / callstack / FunctionNameMapper.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 2015 Ericsson
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 * Contributors:
10 * Alexandre Montplaisir - Initial API and implementation
11 * Marc-Andre Laperle - Map from binary file
12 *******************************************************************************/
13
14 package org.eclipse.tracecompass.internal.tmf.core.callstack;
15
16 import java.io.BufferedReader;
17 import java.io.File;
18 import java.io.FileInputStream;
19 import java.io.FileNotFoundException;
20 import java.io.FileReader;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.eclipse.cdt.core.CCorePlugin;
30 import org.eclipse.cdt.core.IBinaryParser;
31 import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
32 import org.eclipse.cdt.core.IBinaryParser.ISymbol;
33 import org.eclipse.core.runtime.IConfigurationElement;
34 import org.eclipse.core.runtime.IPath;
35 import org.eclipse.core.runtime.ISafeRunnable;
36 import org.eclipse.core.runtime.Path;
37 import org.eclipse.core.runtime.Platform;
38 import org.eclipse.core.runtime.SafeRunner;
39 import org.eclipse.jdt.annotation.Nullable;
40 import org.eclipse.tracecompass.internal.tmf.core.Activator;
41
42 /**
43 * Class containing the different methods to import an address->name mapping.
44 *
45 * @author Alexandre Montplaisir
46 */
47 public class FunctionNameMapper {
48
49 /**
50 * Get the function name mapping from a text file obtained by doing
51 *
52 * <pre>
53 * nm[--demangle][binary] &gt; file.txt
54 * </pre>
55 *
56 * @param mappingFile
57 * The file to import
58 * @return A map&lt;address, function name&gt; of the results
59 */
60 public static @Nullable Map<String, String> mapFromNmTextFile(File mappingFile) {
61 Map<String, String> map = new HashMap<>();
62
63 try (FileReader fr = new FileReader(mappingFile);
64 BufferedReader reader = new BufferedReader(fr);) {
65 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
66 /* Only lines with 3 elements contain addresses */
67 String[] elems = line.split(" ", 3); //$NON-NLS-1$
68 if (elems.length == 3) {
69 String address = stripLeadingZeros(elems[0]);
70 String name = elems[elems.length - 1];
71 map.put(address, name);
72 }
73 }
74 } catch (FileNotFoundException e) {
75 return null;
76 } catch (IOException e) {
77 /* Stop reading the file at this point */
78 }
79
80 if (map.isEmpty()) {
81 return null;
82 }
83 return Collections.unmodifiableMap(map);
84 }
85
86 /**
87 * Strip the leading zeroes from the address
88 * */
89 private static String stripLeadingZeros(String address) {
90 return address.replaceFirst("^0+(?!$)", ""); //$NON-NLS-1$ //$NON-NLS-2$;
91 }
92
93 /**
94 * Get the function name mapping from an executable binary.
95 *
96 * @param file
97 * The file to import
98 * @return A map&lt;address, function name&gt; of the results
99 */
100 public static @Nullable Map<String, String> mapFromBinaryFile(File file) {
101 Map<String, String> map = new HashMap<>();
102 IBinaryParser.IBinaryObject binaryObject = getBinaryObject(file);
103 if (binaryObject != null) {
104 ISymbol[] symbols = binaryObject.getSymbols();
105 for (ISymbol symbol : symbols) {
106 String address = symbol.getAddress().toHexAddressString();
107 /* Remove "0x" */
108 address = address.substring(2);
109 /* Strip the leading zeroes from the address */
110 address = stripLeadingZeros(address);
111 map.put(address, symbol.getName());
112 }
113 }
114
115 return map;
116 }
117
118 private static @Nullable IBinaryParser.IBinaryObject getBinaryObject(File file) {
119 IPath filePath = new Path(file.toString());
120
121 /* Get all the available binary parsers */
122 final List<IBinaryParser> binaryParsers = new ArrayList<>();
123 IConfigurationElement[] elements = Platform.getExtensionRegistry()
124 .getConfigurationElementsFor(CCorePlugin.BINARY_PARSER_UNIQ_ID);
125 for (IConfigurationElement element : elements) {
126 IConfigurationElement[] children = element.getChildren("run"); //$NON-NLS-1$
127 for (final IConfigurationElement run : children) {
128 SafeRunner.run(new ISafeRunnable() {
129 @Override
130 public void run() throws Exception {
131 IBinaryParser binaryParser = (IBinaryParser) run.createExecutableExtension("class"); //$NON-NLS-1$
132 binaryParsers.add(binaryParser);
133 }
134
135 @Override
136 public void handleException(Throwable exception) {
137 Activator.logError("Error creating binary parser", exception); //$NON-NLS-1$
138 }
139 });
140 }
141 }
142
143 /* Find the maximum "hint" buffer size we'll need from all the parsers */
144 int hintBufferSize = 0;
145 for (IBinaryParser parser : binaryParsers) {
146 if (parser.getHintBufferSize() > hintBufferSize) {
147 hintBufferSize = Math.max(hintBufferSize, parser.getHintBufferSize());
148 }
149 }
150
151 /* Read the initial "hint" bytes */
152 byte[] hintBuffer = new byte[hintBufferSize];
153 if (hintBufferSize > 0) {
154 try (InputStream is = new FileInputStream(file) ){
155
156 int count = 0;
157 // Make sure we read up to 'hints' bytes if we possibly can
158 while (count < hintBufferSize) {
159 int bytesRead = is.read(hintBuffer, count, hintBufferSize - count);
160 if (bytesRead < 0) {
161 break;
162 }
163 count += bytesRead;
164 }
165 if (count > 0 && count < hintBuffer.length) {
166 byte[] array = new byte[count];
167 System.arraycopy(hintBuffer, 0, array, 0, count);
168 hintBuffer = array;
169 }
170 } catch (IOException e) {
171 Activator.logError("Error reading initial bytes of binary file", e); //$NON-NLS-1$
172 return null;
173 }
174 }
175
176 /* For all binary parsers, try to get a binary object */
177 for (IBinaryParser parser : binaryParsers) {
178 if (parser.isBinary(hintBuffer, filePath)) {
179 IBinaryFile binFile;
180 try {
181 binFile = parser.getBinary(hintBuffer, filePath);
182 if (binFile != null && binFile instanceof IBinaryParser.IBinaryObject) {
183 return (IBinaryParser.IBinaryObject)binFile;
184 }
185 } catch (IOException e) {
186 Activator.logError("Error parsing binary file", e); //$NON-NLS-1$
187 }
188 }
189 }
190
191 return null;
192 }
193
194 }
This page took 0.056074 seconds and 6 git commands to generate.