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
.Collections
;
25 import java
.util
.HashMap
;
26 import java
.util
.List
;
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
;
43 * Class containing the different methods to import an address->name mapping.
45 * @author Alexandre Montplaisir
47 public class FunctionNameMapper
{
50 * Get the function name mapping from a text file obtained by doing
53 * nm[--demangle][binary] > file.txt
58 * @return A map<address, function name> of the results
60 public static @Nullable Map
<String
, String
> mapFromNmTextFile(File mappingFile
) {
61 Map
<String
, String
> map
= new HashMap
<>();
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
);
74 } catch (FileNotFoundException e
) {
76 } catch (IOException e
) {
77 /* Stop reading the file at this point */
83 return Collections
.unmodifiableMap(map
);
87 * Strip the leading zeroes from the address
89 private static String
stripLeadingZeros(String address
) {
90 return address
.replaceFirst("^0+(?!$)", ""); //$NON-NLS-1$ //$NON-NLS-2$;
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());
118 private static @Nullable IBinaryParser
.IBinaryObject
getBinaryObject(File file
) {
119 IPath filePath
= new Path(file
.toString());
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() {
130 public void run() throws Exception
{
131 IBinaryParser binaryParser
= (IBinaryParser
) run
.createExecutableExtension("class"); //$NON-NLS-1$
132 binaryParsers
.add(binaryParser
);
136 public void handleException(Throwable exception
) {
137 Activator
.logError("Error creating binary parser", exception
); //$NON-NLS-1$
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());
151 /* Read the initial "hint" bytes */
152 byte[] hintBuffer
= new byte[hintBufferSize
];
153 if (hintBufferSize
> 0) {
154 try (InputStream is
= new FileInputStream(file
) ){
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
);
165 if (count
> 0 && count
< hintBuffer
.length
) {
166 byte[] array
= new byte[count
];
167 System
.arraycopy(hintBuffer
, 0, array
, 0, count
);
170 } catch (IOException e
) {
171 Activator
.logError("Error reading initial bytes of binary file", e
); //$NON-NLS-1$
176 /* For all binary parsers, try to get a binary object */
177 for (IBinaryParser parser
: binaryParsers
) {
178 if (parser
.isBinary(hintBuffer
, filePath
)) {
181 binFile
= parser
.getBinary(hintBuffer
, filePath
);
182 if (binFile
!= null && binFile
instanceof IBinaryParser
.IBinaryObject
) {
183 return (IBinaryParser
.IBinaryObject
)binFile
;
185 } catch (IOException e
) {
186 Activator
.logError("Error parsing binary file", e
); //$NON-NLS-1$