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

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, 8 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
« no previous file with comments | « third_party/android_platform/development/scripts/stack_core.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(r'.*/([^/]*)-[0-9]+(\/[^/]*)?\.apk$', device_library_path)
259 if not match:
260 return None
261 return match.group(1)
262
263 def GetMatchingApks(package_name):
241 """Find any APKs which match the package indicated by the device_apk_name. 264 """Find any APKs which match the package indicated by the device_apk_name.
242 265
243 Args: 266 Args:
244 device_apk_name: name of the APK on the device. 267 device_apk_name: name of the APK on the device.
245 268
246 Returns: 269 Returns:
247 A list of APK filenames which could contain the desired library. 270 A list of APK filenames which could contain the desired library.
248 """ 271 """
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( 272 return filter(
254 lambda candidate_apk: 273 lambda candidate_apk:
255 ApkMatchPackageName(GetAapt(), candidate_apk, package_name), 274 ApkMatchPackageName(GetAapt(), candidate_apk, package_name),
256 GetCandidateApks()) 275 GetCandidateApks())
257 276
258 def MapDeviceApkToLibrary(device_apk_name): 277 def MapDeviceApkToLibrary(device_apk_name):
259 """Provide a library name which corresponds with device_apk_name. 278 """Provide a library name which corresponds with device_apk_name.
260 279
261 Args: 280 Args:
262 device_apk_name: name of the APK on the device. 281 device_apk_name: name of the APK on the device.
263 282
264 Returns: 283 Returns:
265 Name of the library which corresponds to that APK. 284 Name of the library which corresponds to that APK.
266 """ 285 """
267 matching_apks = GetMatchingApks(device_apk_name) 286 matching_apks = GetMatchingApks(device_apk_name)
287 logging.debug('MapDeviceApkToLibrary: matching_apks=%s' % matching_apks)
268 for matching_apk in matching_apks: 288 for matching_apk in matching_apks:
269 crazy_lib = GetCrazyLib(matching_apk) 289 crazy_lib = GetCrazyLib(matching_apk)
270 if crazy_lib: 290 if crazy_lib:
271 return crazy_lib 291 return crazy_lib
272 292
273 def GetCandidateLibraries(library_name): 293 def GetCandidateLibraries(library_name):
274 """Returns a list of candidate library filenames. 294 """Returns a list of candidate library filenames.
275 295
276 Args: 296 Args:
277 library_name: basename of the library to match. 297 library_name: basename of the library to match.
278 298
279 Returns: 299 Returns:
280 A list of matching library filenames for library_name. 300 A list of matching library filenames for library_name.
281 """ 301 """
282 return GetCandidates( 302 return GetCandidates(
283 ['lib', 'lib.target'], library_name, 303 ['lib', 'lib.target', '.'], library_name,
284 lambda filename: filter(os.path.exists, [filename])) 304 lambda filename: filter(os.path.exists, [filename]))
285 305
286 def TranslateLibPath(lib): 306 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 307 # 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 308 # 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 309 # 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. 310 # 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 311 # 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 312 # <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. 313 # so we look at the APK badging to see if the package name matches.
302 if re.search('-[0-9]+[.]apk$', library_name): 314 apk = GetApkFromLibrary(lib)
303 mapping = MapDeviceApkToLibrary(library_name) 315 if apk is not None:
316 logging.debug('TranslateLibPath: apk=%s' % apk)
317 mapping = MapDeviceApkToLibrary(apk)
304 if mapping: 318 if mapping:
305 library_name = mapping 319 lib = mapping
320
321 # SymbolInformation(lib, addr) receives lib as the path from symbols
322 # root to the symbols file. This needs to be translated to point to the
323 # correct .so path. If the user doesn't explicitly specify which directory to
324 # use, then use the most recently updated one in one of the known directories.
325 # If the .so is not found somewhere in CHROME_SYMBOLS_DIR, leave it
326 # untranslated in case it is an Android symbol in SYMBOLS_DIR.
327 library_name = os.path.basename(lib)
328
329 logging.debug('TranslateLibPath: lib=%s library_name=%s' % (lib, library_name) )
306 330
307 candidate_libraries = GetCandidateLibraries(library_name) 331 candidate_libraries = GetCandidateLibraries(library_name)
332 logging.debug('TranslateLibPath: candidate_libraries=%s' % candidate_libraries )
308 if not candidate_libraries: 333 if not candidate_libraries:
309 return lib 334 return lib
310 335
311 library_path = os.path.relpath(candidate_libraries[0], SYMBOLS_DIR) 336 library_path = os.path.relpath(candidate_libraries[0], SYMBOLS_DIR)
337 logging.debug('TranslateLibPath: library_path=%s' % library_path)
312 return '/' + library_path 338 return '/' + library_path
313 339
314 def SymbolInformation(lib, addr, get_detailed_info): 340 def SymbolInformation(lib, addr, get_detailed_info):
315 """Look up symbol information about an address. 341 """Look up symbol information about an address.
316 342
317 Args: 343 Args:
318 lib: library (or executable) pathname containing symbols 344 lib: library (or executable) pathname containing symbols
319 addr: string hexidecimal address 345 addr: string hexidecimal address
320 346
321 Returns: 347 Returns:
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 process.stdin.write("\n") 592 process.stdin.write("\n")
567 process.stdin.close() 593 process.stdin.close()
568 demangled_symbol = process.stdout.readline().strip() 594 demangled_symbol = process.stdout.readline().strip()
569 process.stdout.close() 595 process.stdout.close()
570 return demangled_symbol 596 return demangled_symbol
571 597
572 def FormatSymbolWithOffset(symbol, offset): 598 def FormatSymbolWithOffset(symbol, offset):
573 if offset == 0: 599 if offset == 0:
574 return symbol 600 return symbol
575 return "%s+%d" % (symbol, offset) 601 return "%s+%d" % (symbol, offset)
OLDNEW
« no previous file with comments | « third_party/android_platform/development/scripts/stack_core.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698