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

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

Issue 1006603002: Fix stack tool for library in apk crashes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 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 logging
24 import os 25 import os
25 import re 26 import re
27 import struct
26 import subprocess 28 import subprocess
27 import zipfile 29 import zipfile
28 30
29 CHROME_SRC = os.path.join(os.path.realpath(os.path.dirname(__file__)), 31 CHROME_SRC = os.path.join(os.path.realpath(os.path.dirname(__file__)),
30 os.pardir, os.pardir, os.pardir, os.pardir) 32 os.pardir, os.pardir, os.pardir, os.pardir)
31 ANDROID_BUILD_TOP = CHROME_SRC 33 ANDROID_BUILD_TOP = CHROME_SRC
32 SYMBOLS_DIR = CHROME_SRC 34 SYMBOLS_DIR = CHROME_SRC
33 CHROME_SYMBOLS_DIR = CHROME_SRC 35 CHROME_SYMBOLS_DIR = CHROME_SRC
34 36
35 ARCH = "arm" 37 ARCH = "arm"
36 38
37 TOOLCHAIN_INFO = None 39 TOOLCHAIN_INFO = None
38 40
41 # See:
42 # http://bugs.python.org/issue14315
43 # https://hg.python.org/cpython/rev/6dd5e9556a60#l2.8
44 def PatchZipFile():
45 oldDecodeExtra = zipfile.ZipInfo._decodeExtra
46 def decodeExtra(self):
47 try:
48 oldDecodeExtra(self)
49 except struct.error:
50 pass
51 zipfile.ZipInfo._decodeExtra = decodeExtra
52 PatchZipFile()
53
39 def Uname(): 54 def Uname():
40 """'uname' for constructing prebuilt/<...> and out/host/<...> paths.""" 55 """'uname' for constructing prebuilt/<...> and out/host/<...> paths."""
41 uname = os.uname()[0] 56 uname = os.uname()[0]
42 if uname == "Darwin": 57 if uname == "Darwin":
43 proc = os.uname()[-1] 58 proc = os.uname()[-1]
44 if proc == "i386" or proc == "x86_64": 59 if proc == "i386" or proc == "x86_64":
45 return "darwin-x86" 60 return "darwin-x86"
46 return "darwin-ppc" 61 return "darwin-ppc"
47 if uname == "Linux": 62 if uname == "Linux":
48 return "linux-x86" 63 return "linux-x86"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 known_toolchains = [ 129 known_toolchains = [
115 ("x86_64-" + gcc_version, "x86_64", "x86_64-linux-android") 130 ("x86_64-" + gcc_version, "x86_64", "x86_64-linux-android")
116 ] 131 ]
117 elif ARCH == "mips": 132 elif ARCH == "mips":
118 known_toolchains = [ 133 known_toolchains = [
119 ("mipsel-linux-android-" + gcc_version, "mips", "mipsel-linux-android") 134 ("mipsel-linux-android-" + gcc_version, "mips", "mipsel-linux-android")
120 ] 135 ]
121 else: 136 else:
122 known_toolchains = [] 137 known_toolchains = []
123 138
139 logging.debug('FindToolcahin: known_toolchains=%s' % known_toolchains)
124 # Look for addr2line to check for valid toolchain path. 140 # Look for addr2line to check for valid toolchain path.
125 for (label, platform, target) in known_toolchains: 141 for (label, platform, target) in known_toolchains:
126 toolchain_info = (label, platform, target); 142 toolchain_info = (label, platform, target);
127 if os.path.exists(ToolPath("addr2line", toolchain_info)): 143 if os.path.exists(ToolPath("addr2line", toolchain_info)):
128 TOOLCHAIN_INFO = toolchain_info 144 TOOLCHAIN_INFO = toolchain_info
129 print "Using toolchain from :" + ToolPath("", TOOLCHAIN_INFO) 145 print "Using toolchain from :" + ToolPath("", TOOLCHAIN_INFO)
130 return toolchain_info 146 return toolchain_info
131 147
132 raise Exception("Could not find tool chain") 148 raise Exception("Could not find tool chain")
133 149
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 out_dir = os.path.join(CHROME_SYMBOLS_DIR, out_dir) 215 out_dir = os.path.join(CHROME_SYMBOLS_DIR, out_dir)
200 buildtype = os.environ.get('BUILDTYPE') 216 buildtype = os.environ.get('BUILDTYPE')
201 if buildtype: 217 if buildtype:
202 buildtype_list = [ buildtype ] 218 buildtype_list = [ buildtype ]
203 else: 219 else:
204 buildtype_list = [ 'Debug', 'Release' ] 220 buildtype_list = [ 'Debug', 'Release' ]
205 221
206 candidates = PathListJoin([out_dir], buildtype_list) + [CHROME_SYMBOLS_DIR] 222 candidates = PathListJoin([out_dir], buildtype_list) + [CHROME_SYMBOLS_DIR]
207 candidates = PathListJoin(candidates, dirs) 223 candidates = PathListJoin(candidates, dirs)
208 candidates = PathListJoin(candidates, [filepart]) 224 candidates = PathListJoin(candidates, [filepart])
225 logging.debug('GetCandidates: prefiltered candidates = %s' % candidates)
209 candidates = list( 226 candidates = list(
210 itertools.chain.from_iterable(map(candidate_fun, candidates))) 227 itertools.chain.from_iterable(map(candidate_fun, candidates)))
211 candidates = sorted(candidates, key=os.path.getmtime, reverse=True) 228 candidates = sorted(candidates, key=os.path.getmtime, reverse=True)
212 return candidates 229 return candidates
213 230
214 def GetCandidateApks(): 231 def GetCandidateApks():
215 """Returns a list of APKs which could contain the library. 232 """Returns a list of APKs which could contain the library.
216 233
217 Args: 234 Args:
218 None 235 None
(...skipping 11 matching lines...) Expand all
230 247
231 Returns: 248 Returns:
232 Name of the first library which would be crazy loaded from this APK. 249 Name of the first library which would be crazy loaded from this APK.
233 """ 250 """
234 zip_file = zipfile.ZipFile(apk_filename, 'r') 251 zip_file = zipfile.ZipFile(apk_filename, 'r')
235 for filename in zip_file.namelist(): 252 for filename in zip_file.namelist():
236 match = re.match('lib/[^/]*/crazy.(lib.*[.]so)', filename) 253 match = re.match('lib/[^/]*/crazy.(lib.*[.]so)', filename)
237 if match: 254 if match:
238 return match.group(1) 255 return match.group(1)
239 256
240 def GetMatchingApks(device_apk_name): 257 def GetApkFromLibrary(device_library_path):
258 match = re.match('.*/([^/]*)-[0-9]+[.]apk$', device_library_path)
259 if not match:
260 match = re.match('.*/([^/]*)-[0-9]+\/[^/]*\.apk$', device_library_path)
rmcilroy 2015/03/12 21:50:14 Could you put some comments with examples for what
261 if not match:
262 return None
263 return match.group(1)
264
265 def GetMatchingApks(package_name):
241 """Find any APKs which match the package indicated by the device_apk_name. 266 """Find any APKs which match the package indicated by the device_apk_name.
242 267
243 Args: 268 Args:
244 device_apk_name: name of the APK on the device. 269 device_apk_name: name of the APK on the device.
245 270
246 Returns: 271 Returns:
247 A list of APK filenames which could contain the desired library. 272 A list of APK filenames which could contain the desired library.
248 """ 273 """
249 match = re.match('(.*)-[0-9]+[.]apk$', device_apk_name)
250 if not match:
251 return None
252 package_name = match.group(1)
253 return filter( 274 return filter(
254 lambda candidate_apk: 275 lambda candidate_apk:
255 ApkMatchPackageName(GetAapt(), candidate_apk, package_name), 276 ApkMatchPackageName(GetAapt(), candidate_apk, package_name),
256 GetCandidateApks()) 277 GetCandidateApks())
257 278
258 def MapDeviceApkToLibrary(device_apk_name): 279 def MapDeviceApkToLibrary(device_apk_name):
259 """Provide a library name which corresponds with device_apk_name. 280 """Provide a library name which corresponds with device_apk_name.
260 281
261 Args: 282 Args:
262 device_apk_name: name of the APK on the device. 283 device_apk_name: name of the APK on the device.
263 284
264 Returns: 285 Returns:
265 Name of the library which corresponds to that APK. 286 Name of the library which corresponds to that APK.
266 """ 287 """
267 matching_apks = GetMatchingApks(device_apk_name) 288 matching_apks = GetMatchingApks(device_apk_name)
289 logging.debug('MapDeviceApkToLibrary: matching_apks=%s' % matching_apks)
268 for matching_apk in matching_apks: 290 for matching_apk in matching_apks:
269 crazy_lib = GetCrazyLib(matching_apk) 291 crazy_lib = GetCrazyLib(matching_apk)
270 if crazy_lib: 292 if crazy_lib:
271 return crazy_lib 293 return crazy_lib
272 294
273 def GetCandidateLibraries(library_name): 295 def GetCandidateLibraries(library_name):
274 """Returns a list of candidate library filenames. 296 """Returns a list of candidate library filenames.
275 297
276 Args: 298 Args:
277 library_name: basename of the library to match. 299 library_name: basename of the library to match.
278 300
279 Returns: 301 Returns:
280 A list of matching library filenames for library_name. 302 A list of matching library filenames for library_name.
281 """ 303 """
282 return GetCandidates( 304 return GetCandidates(
283 ['lib', 'lib.target'], library_name, 305 ['lib', 'lib.target', '.'], library_name,
284 lambda filename: filter(os.path.exists, [filename])) 306 lambda filename: filter(os.path.exists, [filename]))
285 307
286 def TranslateLibPath(lib): 308 def TranslateLibPath(lib):
287 # SymbolInformation(lib, addr) receives lib as the path from symbols
288 # root to the symbols file. This needs to be translated to point to the
289 # correct .so path. If the user doesn't explicitly specify which directory to
290 # use, then use the most recently updated one in one of the known directories.
291 # If the .so is not found somewhere in CHROME_SYMBOLS_DIR, leave it
292 # untranslated in case it is an Android symbol in SYMBOLS_DIR.
293 library_name = os.path.basename(lib)
294
295 # The filename in the stack trace maybe an APK name rather than a library 309 # The filename in the stack trace maybe an APK name rather than a library
296 # name. This happens when the library was loaded directly from inside the 310 # name. This happens when the library was loaded directly from inside the
297 # APK. If this is the case we try to figure out the library name by looking 311 # APK. If this is the case we try to figure out the library name by looking
298 # for a matching APK file and finding the name of the library in contains. 312 # for a matching APK file and finding the name of the library in contains.
299 # The name of the APK file on the device is of the form 313 # The name of the APK file on the device is of the form
300 # <package_name>-<number>.apk. The APK file on the host may have any name 314 # <package_name>-<number>.apk. The APK file on the host may have any name
301 # so we look at the APK badging to see if the package name matches. 315 # so we look at the APK badging to see if the package name matches.
302 if re.search('-[0-9]+[.]apk$', library_name): 316 apk = GetApkFromLibrary(lib)
303 mapping = MapDeviceApkToLibrary(library_name) 317 if apk is not None:
318 logging.debug('TranslateLibPath: apk=%s' % apk)
319 mapping = MapDeviceApkToLibrary(apk)
304 if mapping: 320 if mapping:
305 library_name = mapping 321 lib = mapping
322
323 # SymbolInformation(lib, addr) receives lib as the path from symbols
324 # root to the symbols file. This needs to be translated to point to the
325 # correct .so path. If the user doesn't explicitly specify which directory to
326 # use, then use the most recently updated one in one of the known directories.
327 # If the .so is not found somewhere in CHROME_SYMBOLS_DIR, leave it
328 # untranslated in case it is an Android symbol in SYMBOLS_DIR.
329 library_name = os.path.basename(lib)
330
331 logging.debug('TranslateLibPath: lib=%s library_name=%s' % (lib, library_name) )
306 332
307 candidate_libraries = GetCandidateLibraries(library_name) 333 candidate_libraries = GetCandidateLibraries(library_name)
334 logging.debug('TranslateLibPath: candidate_libraries=%s' % candidate_libraries )
308 if not candidate_libraries: 335 if not candidate_libraries:
309 return lib 336 return lib
310 337
311 library_path = os.path.relpath(candidate_libraries[0], SYMBOLS_DIR) 338 library_path = os.path.relpath(candidate_libraries[0], SYMBOLS_DIR)
339 logging.debug('TranslateLibPath: library_path=%s' % library_path)
312 return '/' + library_path 340 return '/' + library_path
313 341
314 def SymbolInformation(lib, addr, get_detailed_info): 342 def SymbolInformation(lib, addr, get_detailed_info):
315 """Look up symbol information about an address. 343 """Look up symbol information about an address.
316 344
317 Args: 345 Args:
318 lib: library (or executable) pathname containing symbols 346 lib: library (or executable) pathname containing symbols
319 addr: string hexidecimal address 347 addr: string hexidecimal address
320 348
321 Returns: 349 Returns:
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 process.stdin.write("\n") 594 process.stdin.write("\n")
567 process.stdin.close() 595 process.stdin.close()
568 demangled_symbol = process.stdout.readline().strip() 596 demangled_symbol = process.stdout.readline().strip()
569 process.stdout.close() 597 process.stdout.close()
570 return demangled_symbol 598 return demangled_symbol
571 599
572 def FormatSymbolWithOffset(symbol, offset): 600 def FormatSymbolWithOffset(symbol, offset):
573 if offset == 0: 601 if offset == 0:
574 return symbol 602 return symbol
575 return "%s+%d" % (symbol, offset) 603 return "%s+%d" % (symbol, offset)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698