1 /*******************************************************************************
2 * Copyright (c) 2013, 2015 Ericsson
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
10 * Alexandre Montplaisir - Initial API and implementation
11 * Marc-Andre Laperle - Map from binary file
12 *******************************************************************************/
14 package org
.eclipse
.tracecompass
.internal
.tmf
.core
.callstack
;
16 import java
.io
.BufferedReader
;
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
.HashMap
;
25 import java
.util
.List
;
27 import java
.util
.regex
.Pattern
;
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
;
42 import com
.google
.common
.collect
.ImmutableMap
;
45 * Class containing the different methods to import an address->name mapping.
47 * @author Alexandre Montplaisir
49 public final class FunctionNameMapper
{
51 private FunctionNameMapper() {}
53 private static final Pattern REMOVE_ZEROS_PATTERN
= Pattern
.compile("^0+(?!$)"); //$NON-NLS-1$
56 * Get the function name mapping from a text file obtained by doing
59 * nm[--demangle][binary] > file.txt
64 * @return A map<address, function name> of the results
66 public static @Nullable Map
<String
, String
> mapFromNmTextFile(File mappingFile
) {
67 Map
<String
, String
> map
= new HashMap
<>();
69 try (FileReader fr
= new FileReader(mappingFile
);
70 BufferedReader reader
= new BufferedReader(fr
);) {
71 for (String line
= reader
.readLine(); line
!= null; line
= reader
.readLine()) {
73 /* Only lines with 3 elements contain addresses */
74 String
[] elems
= line
.split(" ", 3); //$NON-NLS-1$
75 if (elems
.length
== 3) {
76 String address
= stripLeadingZeros(elems
[0]);
77 String name
= elems
[elems
.length
- 1];
78 map
.put(address
, name
);
81 } catch (FileNotFoundException e
) {
83 } catch (IOException e
) {
84 /* Stop reading the file at this point */
90 return ImmutableMap
.copyOf(map
);
94 * Get the function name mapping from an executable binary.
98 * @return A map<address, function name> of the results
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();
108 address
= address
.substring(2);
109 /* Strip the leading zeroes from the address */
110 address
= stripLeadingZeros(address
);
111 map
.put(address
, symbol
.getName());
115 return ImmutableMap
.copyOf(map
);
120 * Strip the leading zeroes from the address
122 private static String
stripLeadingZeros(String address
) {
123 return REMOVE_ZEROS_PATTERN
.matcher(address
).replaceFirst(""); //$NON-NLS-1$
126 private static @Nullable IBinaryParser
.IBinaryObject
getBinaryObject(File file
) {
127 IPath filePath
= new Path(file
.toString());
129 /* Get all the available binary parsers */
130 final List
<IBinaryParser
> binaryParsers
= new ArrayList
<>();
131 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
132 .getConfigurationElementsFor(CCorePlugin
.BINARY_PARSER_UNIQ_ID
);
133 for (IConfigurationElement element
: elements
) {
134 IConfigurationElement
[] children
= element
.getChildren("run"); //$NON-NLS-1$
135 for (final IConfigurationElement run
: children
) {
136 SafeRunner
.run(new ISafeRunnable() {
138 public void run() throws Exception
{
139 IBinaryParser binaryParser
= (IBinaryParser
) run
.createExecutableExtension("class"); //$NON-NLS-1$
140 binaryParsers
.add(binaryParser
);
144 public void handleException(Throwable exception
) {
145 Activator
.logError("Error creating binary parser", exception
); //$NON-NLS-1$
151 /* Find the maximum "hint" buffer size we'll need from all the parsers */
152 int hintBufferSize
= 0;
153 for (IBinaryParser parser
: binaryParsers
) {
154 if (parser
.getHintBufferSize() > hintBufferSize
) {
155 hintBufferSize
= Math
.max(hintBufferSize
, parser
.getHintBufferSize());
159 /* Read the initial "hint" bytes */
160 byte[] hintBuffer
= new byte[hintBufferSize
];
161 if (hintBufferSize
> 0) {
162 try (InputStream is
= new FileInputStream(file
) ){
165 // Make sure we read up to 'hints' bytes if we possibly can
166 while (count
< hintBufferSize
) {
167 int bytesRead
= is
.read(hintBuffer
, count
, hintBufferSize
- count
);
173 if (count
> 0 && count
< hintBuffer
.length
) {
174 byte[] array
= new byte[count
];
175 System
.arraycopy(hintBuffer
, 0, array
, 0, count
);
178 } catch (IOException e
) {
179 Activator
.logError("Error reading initial bytes of binary file", e
); //$NON-NLS-1$
184 /* For all binary parsers, try to get a binary object */
185 for (IBinaryParser parser
: binaryParsers
) {
186 if (parser
.isBinary(hintBuffer
, filePath
)) {
189 binFile
= parser
.getBinary(hintBuffer
, filePath
);
190 if (binFile
instanceof IBinaryParser
.IBinaryObject
) {
191 return (IBinaryParser
.IBinaryObject
)binFile
;
193 } catch (IOException e
) {
194 Activator
.logError("Error parsing binary file", e
); //$NON-NLS-1$