Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: third_party/android_platform/development/scripts/symbol.py

Issue 822713002: Update from https://crrev.com/309415 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # 2 #
3 # Copyright (C) 2013 The Android Open Source Project 3 # Copyright (C) 2013 The Android Open Source Project
4 # 4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License. 6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at 7 # You may obtain a copy of the License at
8 # 8 #
9 # http://www.apache.org/licenses/LICENSE-2.0 9 # http://www.apache.org/licenses/LICENSE-2.0
10 # 10 #
11 # Unless required by applicable law or agreed to in writing, software 11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, 12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and 14 # See the License for the specific language governing permissions and
15 # limitations under the License. 15 # limitations under the License.
16 16
17 """Module for looking up symbolic debugging information. 17 """Module for looking up symbolic debugging information.
18 18
19 The information can include symbol names, offsets, and source locations. 19 The information can include symbol names, offsets, and source locations.
20 """ 20 """
21 21
22 import glob 22 import glob
23 import itertools 23 import itertools
24 import os 24 import os
25 import re 25 import re
26 import subprocess 26 import subprocess
27 import zipfile 27 import zipfile
28 28
29 CHROME_SRC = os.path.join(os.path.realpath(os.path.dirname(__file__)), 29 CHROME_SRC = os.path.join(os.path.realpath(os.path.dirname(__file__)),
30 os.pardir, os.pardir) 30 os.pardir, os.pardir, os.pardir, os.pardir)
31 ANDROID_BUILD_TOP = CHROME_SRC 31 ANDROID_BUILD_TOP = CHROME_SRC
32 SYMBOLS_DIR = CHROME_SRC 32 SYMBOLS_DIR = CHROME_SRC
33 CHROME_SYMBOLS_DIR = CHROME_SRC 33 CHROME_SYMBOLS_DIR = CHROME_SRC
34 34
35 ARCH = "arm" 35 ARCH = "arm"
36 36
37 TOOLCHAIN_INFO = None 37 TOOLCHAIN_INFO = None
38 38
39 def Uname(): 39 def Uname():
40 """'uname' for constructing prebuilt/<...> and out/host/<...> paths.""" 40 """'uname' for constructing prebuilt/<...> and out/host/<...> paths."""
(...skipping 16 matching lines...) Expand all
57 toolchain_prefix = "arm-linux-androideabi" 57 toolchain_prefix = "arm-linux-androideabi"
58 ndk = "ndk" 58 ndk = "ndk"
59 elif ARCH == "arm64": 59 elif ARCH == "arm64":
60 toolchain_source = "aarch64-linux-android-4.9" 60 toolchain_source = "aarch64-linux-android-4.9"
61 toolchain_prefix = "aarch64-linux-android" 61 toolchain_prefix = "aarch64-linux-android"
62 ndk = "ndk" 62 ndk = "ndk"
63 elif ARCH == "x86": 63 elif ARCH == "x86":
64 toolchain_source = "x86-4.9" 64 toolchain_source = "x86-4.9"
65 toolchain_prefix = "i686-linux-android" 65 toolchain_prefix = "i686-linux-android"
66 ndk = "ndk" 66 ndk = "ndk"
67 elif ARCH == "x86_64" or ARCH == "x64": 67 elif ARCH == "x86_64":
68 toolchain_source = "x86_64-4.9" 68 toolchain_source = "x86_64-4.9"
69 toolchain_prefix = "x86_64-linux-android" 69 toolchain_prefix = "x86_64-linux-android"
70 ndk = "ndk" 70 ndk = "ndk"
71 elif ARCH == "mips": 71 elif ARCH == "mips":
72 toolchain_source = "mipsel-linux-android-4.9" 72 toolchain_source = "mipsel-linux-android-4.9"
73 toolchain_prefix = "mipsel-linux-android" 73 toolchain_prefix = "mipsel-linux-android"
74 ndk = "ndk" 74 ndk = "ndk"
75 else: 75 else:
76 raise Exception("Could not find tool chain") 76 raise Exception("Could not find tool chain")
77 77
(...skipping 25 matching lines...) Expand all
103 ("aarch64-linux-android-" + gcc_version, "aarch64", "aarch64-linux-android ") 103 ("aarch64-linux-android-" + gcc_version, "aarch64", "aarch64-linux-android ")
104 ] 104 ]
105 elif ARCH == "arm": 105 elif ARCH == "arm":
106 known_toolchains = [ 106 known_toolchains = [
107 ("arm-linux-androideabi-" + gcc_version, "arm", "arm-linux-androideabi") 107 ("arm-linux-androideabi-" + gcc_version, "arm", "arm-linux-androideabi")
108 ] 108 ]
109 elif ARCH =="x86": 109 elif ARCH =="x86":
110 known_toolchains = [ 110 known_toolchains = [
111 ("x86-" + gcc_version, "x86", "i686-linux-android") 111 ("x86-" + gcc_version, "x86", "i686-linux-android")
112 ] 112 ]
113 elif ARCH =="x86_64" or ARCH =="x64": 113 elif ARCH =="x86_64":
114 known_toolchains = [ 114 known_toolchains = [
115 ("x86_64-" + gcc_version, "x86_64", "x86_64-linux-android") 115 ("x86_64-" + gcc_version, "x86_64", "x86_64-linux-android")
116 ] 116 ]
117 elif ARCH == "mips": 117 elif ARCH == "mips":
118 known_toolchains = [ 118 known_toolchains = [
119 ("mipsel-linux-android-" + gcc_version, "mips", "mipsel-linux-android") 119 ("mipsel-linux-android-" + gcc_version, "mips", "mipsel-linux-android")
120 ] 120 ]
121 else: 121 else:
122 known_toolchains = [] 122 known_toolchains = []
123 123
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 prefix_list: list of path prefixes. 177 prefix_list: list of path prefixes.
178 suffix_list: list of path suffixes. 178 suffix_list: list of path suffixes.
179 179
180 Returns: 180 Returns:
181 List of paths each of which joins a prefix with a suffix. 181 List of paths each of which joins a prefix with a suffix.
182 """ 182 """
183 return [ 183 return [
184 os.path.join(prefix, suffix) 184 os.path.join(prefix, suffix)
185 for prefix in prefix_list for suffix in suffix_list ] 185 for prefix in prefix_list for suffix in suffix_list ]
186 186
187 def GetCandidates(filepart, candidate_fun, relative_dirs=None): 187 def GetCandidates(dirs, filepart, candidate_fun):
188 """Returns a list of candidate filenames. 188 """Returns a list of candidate filenames.
189 189
190 Args: 190 Args:
191 dirs: a list of the directory part of the pathname.
191 filepart: the file part of the pathname. 192 filepart: the file part of the pathname.
192 candidate_fun: a function to apply to each candidate, returns a list. 193 candidate_fun: a function to apply to each candidate, returns a list.
193 relative_dirs: a list of relative directory names to search from.
194 194
195 Returns: 195 Returns:
196 A list of candidate files ordered by modification time, newest first. 196 A list of candidate files ordered by modification time, newest first.
197 """ 197 """
198 candidates = [CHROME_SYMBOLS_DIR] 198 out_dir = os.environ.get('CHROMIUM_OUT_DIR', 'out')
199 out_dir = os.path.join(CHROME_SYMBOLS_DIR, out_dir)
200 buildtype = os.environ.get('BUILDTYPE')
201 if buildtype:
202 buildtype_list = [ buildtype ]
203 else:
204 buildtype_list = [ 'Debug', 'Release' ]
199 205
200 # Add the two possible mojo outdirs. 206 candidates = PathListJoin([out_dir], buildtype_list) + [CHROME_SYMBOLS_DIR]
201 out_dir = os.path.join(CHROME_SYMBOLS_DIR, 'out') 207 candidates = PathListJoin(candidates, dirs)
202 candidates += PathListJoin([out_dir], ['android_Debug', 'android_Release'])
203
204 if relative_dirs:
205 candidates = PathListJoin(candidates, relative_dirs)
206
207 candidates = PathListJoin(candidates, [filepart]) 208 candidates = PathListJoin(candidates, [filepart])
208 candidates = list( 209 candidates = list(
209 itertools.chain.from_iterable(map(candidate_fun, candidates))) 210 itertools.chain.from_iterable(map(candidate_fun, candidates)))
210 candidates = sorted(candidates, key=os.path.getmtime, reverse=True) 211 candidates = sorted(candidates, key=os.path.getmtime, reverse=True)
212 # candidates = ['/usr/local/google/home/qsr/programmes/mojo/src/out/android_De bug/libmojo_shell.so']
211 return candidates 213 return candidates
212 214
213 def GetCandidateApks(): 215 def GetCandidateApks():
214 """Returns a list of APKs which could contain the library. 216 """Returns a list of APKs which could contain the library.
215 217
216 Args: 218 Args:
217 None 219 None
218 220
219 Returns: 221 Returns:
220 list of APK filename which could contain the library. 222 list of APK filename which could contain the library.
221 """ 223 """
222 return GetCandidates('*.apk', glob.glob, relative_dirs=['apks']) 224 return GetCandidates(['apks'], '*.apk', glob.glob)
223 225
224 def GetCrazyLib(apk_filename): 226 def GetCrazyLib(apk_filename):
225 """Returns the name of the first crazy library from this APK. 227 """Returns the name of the first crazy library from this APK.
226 228
227 Args: 229 Args:
228 apk_filename: name of an APK file. 230 apk_filename: name of an APK file.
229 231
230 Returns: 232 Returns:
231 Name of the first library which would be crazy loaded from this APK. 233 Name of the first library which would be crazy loaded from this APK.
232 """ 234 """
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 def GetCandidateLibraries(library_name): 274 def GetCandidateLibraries(library_name):
273 """Returns a list of candidate library filenames. 275 """Returns a list of candidate library filenames.
274 276
275 Args: 277 Args:
276 library_name: basename of the library to match. 278 library_name: basename of the library to match.
277 279
278 Returns: 280 Returns:
279 A list of matching library filenames for library_name. 281 A list of matching library filenames for library_name.
280 """ 282 """
281 return GetCandidates( 283 return GetCandidates(
282 library_name, 284 ['', 'lib', 'lib.target'], library_name,
283 lambda filename: filter(os.path.exists, [filename])) 285 lambda filename: filter(os.path.exists, [filename]))
284 286
285 def TranslatePathFromDeviceToLocal(lib): 287 def TranslateLibPath(lib):
286 """Maps a path as seen on the device to a path on the local file system 288 # SymbolInformation(lib, addr) receives lib as the path from symbols
287 containing symbols. 289 # root to the symbols file. This needs to be translated to point to the
288 290 # correct .so path. If the user doesn't explicitly specify which directory to
289 Args: 291 # use, then use the most recently updated one in one of the known directories.
290 lib: library (or executable) pathname from device. 292 # If the .so is not found somewhere in CHROME_SYMBOLS_DIR, leave it
291 """ 293 # untranslated in case it is an Android symbol in SYMBOLS_DIR.
292
293 # SymbolInformation(lib, addr) receives lib that is either a basename or
294 # the path from symbols root to the symbols file. This needs to be translated
295 # to point to the correct .so path. If the user doesn't explicitly specify
296 # which directory to use, then use the most recently updated one in one of
297 # the known directories.
298 library_name = os.path.basename(lib) 294 library_name = os.path.basename(lib)
299 295
300 # The filename in the stack trace maybe an APK name rather than a library 296 # The filename in the stack trace maybe an APK name rather than a library
301 # name. This happens when the library was loaded directly from inside the 297 # name. This happens when the library was loaded directly from inside the
302 # APK. If this is the case we try to figure out the library name by looking 298 # APK. If this is the case we try to figure out the library name by looking
303 # for a matching APK file and finding the name of the library in contains. 299 # for a matching APK file and finding the name of the library in contains.
304 # The name of the APK file on the device is of the form 300 # The name of the APK file on the device is of the form
305 # <package_name>-<number>.apk. The APK file on the host may have any name 301 # <package_name>-<number>.apk. The APK file on the host may have any name
306 # so we look at the APK badging to see if the package name matches. 302 # so we look at the APK badging to see if the package name matches.
307 if re.search('-[0-9]+[.]apk$', library_name): 303 if re.search('-[0-9]+[.]apk$', library_name):
308 mapping = MapDeviceApkToLibrary(library_name) 304 mapping = MapDeviceApkToLibrary(library_name)
309 if mapping: 305 if mapping:
310 library_name = mapping 306 library_name = mapping
311 307
312 candidate_libraries = GetCandidateLibraries(library_name) 308 candidate_libraries = GetCandidateLibraries(library_name)
313 return (candidate_libraries[0] if candidate_libraries else 309 if not candidate_libraries:
314 os.path.join(SYMBOLS_DIR, lib)) 310 return lib
311
312 library_path = os.path.relpath(candidate_libraries[0], SYMBOLS_DIR)
313 return '/' + library_path
315 314
316 def SymbolInformation(lib, addr, get_detailed_info): 315 def SymbolInformation(lib, addr, get_detailed_info):
317 """Look up symbol information about an address. 316 """Look up symbol information about an address.
318 317
319 Args: 318 Args:
320 lib: library (or executable) pathname containing symbols 319 lib: library (or executable) pathname containing symbols
321 addr: string hexidecimal address 320 addr: string hexidecimal address
322 321
323 Returns: 322 Returns:
324 A list of the form [(source_symbol, source_location, 323 A list of the form [(source_symbol, source_location,
325 object_symbol_with_offset)]. 324 object_symbol_with_offset)].
326 325
327 If the function has been inlined then the list may contain 326 If the function has been inlined then the list may contain
328 more than one element with the symbols for the most deeply 327 more than one element with the symbols for the most deeply
329 nested inlined location appearing first. The list is 328 nested inlined location appearing first. The list is
330 always non-empty, even if no information is available. 329 always non-empty, even if no information is available.
331 330
332 Usually you want to display the source_location and 331 Usually you want to display the source_location and
333 object_symbol_with_offset from the last element in the list. 332 object_symbol_with_offset from the last element in the list.
334 """ 333 """
335 lib = TranslatePathFromDeviceToLocal(lib) 334 lib = TranslateLibPath(lib)
336 info = SymbolInformationForSet(lib, set([addr]), get_detailed_info) 335 info = SymbolInformationForSet(lib, set([addr]), get_detailed_info)
337 return (info and info.get(addr)) or [(None, None, None)] 336 return (info and info.get(addr)) or [(None, None, None)]
338 337
339 338
340 def SymbolInformationForSet(lib, unique_addrs, get_detailed_info): 339 def SymbolInformationForSet(lib, unique_addrs, get_detailed_info):
341 """Look up symbol information for a set of addresses from the given library. 340 """Look up symbol information for a set of addresses from the given library.
342 341
343 Args: 342 Args:
344 lib: library (or executable) pathname containing symbols 343 lib: library (or executable) pathname containing symbols
345 unique_addrs: set of hexidecimal addresses 344 unique_addrs: set of hexidecimal addresses
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 415
417 Returns: 416 Returns:
418 A dictionary of the form {addr: [(symbol, file:line)]} where 417 A dictionary of the form {addr: [(symbol, file:line)]} where
419 each address has a list of associated symbols and locations 418 each address has a list of associated symbols and locations
420 or an empty list if no symbol information was found. 419 or an empty list if no symbol information was found.
421 420
422 If the function has been inlined then the list may contain 421 If the function has been inlined then the list may contain
423 more than one element with the symbols for the most deeply 422 more than one element with the symbols for the most deeply
424 nested inlined location appearing first. 423 nested inlined location appearing first.
425 """ 424 """
426 if not lib or not os.path.isfile(lib): 425 if not lib:
426 return None
427
428
429 symbols = SYMBOLS_DIR + lib
430 if not os.path.isfile(symbols):
427 return None 431 return None
428 432
429 (label, platform, target) = FindToolchain() 433 (label, platform, target) = FindToolchain()
430 cmd = [ToolPath("addr2line"), "--functions", "--inlines", 434 cmd = [ToolPath("addr2line"), "--functions", "--inlines",
431 "--demangle", "--exe=" + lib] 435 "--demangle", "--exe=" + symbols]
432 child = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 436 child = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
433 437
434 result = {} 438 result = {}
435 addrs = sorted(unique_addrs) 439 addrs = sorted(unique_addrs)
436 for addr in addrs: 440 for addr in addrs:
437 child.stdin.write("0x%s\n" % addr) 441 child.stdin.write("0x%s\n" % addr)
438 child.stdin.flush() 442 child.stdin.flush()
439 records = [] 443 records = []
440 first = True 444 first = True
441 while True: 445 while True:
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 process.stdin.write("\n") 567 process.stdin.write("\n")
564 process.stdin.close() 568 process.stdin.close()
565 demangled_symbol = process.stdout.readline().strip() 569 demangled_symbol = process.stdout.readline().strip()
566 process.stdout.close() 570 process.stdout.close()
567 return demangled_symbol 571 return demangled_symbol
568 572
569 def FormatSymbolWithOffset(symbol, offset): 573 def FormatSymbolWithOffset(symbol, offset):
570 if offset == 0: 574 if offset == 0:
571 return symbol 575 return symbol
572 return "%s+%d" % (symbol, offset) 576 return "%s+%d" % (symbol, offset)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698