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

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

Issue 401003003: Stack trace support for libraries loaded directly from APKs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Whitespace changes Created 6 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « third_party/android_platform/README.chromium ('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
23 import itertools
22 import os 24 import os
23 import re 25 import re
24 import subprocess 26 import subprocess
27 import zipfile
25 28
26 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__)),
27 os.pardir, os.pardir, os.pardir, os.pardir) 30 os.pardir, os.pardir, os.pardir, os.pardir)
28 ANDROID_BUILD_TOP = CHROME_SRC 31 ANDROID_BUILD_TOP = CHROME_SRC
29 SYMBOLS_DIR = CHROME_SRC 32 SYMBOLS_DIR = CHROME_SRC
30 CHROME_SYMBOLS_DIR = CHROME_SRC 33 CHROME_SYMBOLS_DIR = CHROME_SRC
31 34
32 ARCH = "arm" 35 ARCH = "arm"
33 36
34 TOOLCHAIN_INFO = None 37 TOOLCHAIN_INFO = None
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 # Look for addr2line to check for valid toolchain path. 126 # Look for addr2line to check for valid toolchain path.
124 for (label, platform, target) in known_toolchains: 127 for (label, platform, target) in known_toolchains:
125 toolchain_info = (label, platform, target); 128 toolchain_info = (label, platform, target);
126 if os.path.exists(ToolPath("addr2line", toolchain_info)): 129 if os.path.exists(ToolPath("addr2line", toolchain_info)):
127 TOOLCHAIN_INFO = toolchain_info 130 TOOLCHAIN_INFO = toolchain_info
128 print "Using toolchain from :" + ToolPath("", TOOLCHAIN_INFO) 131 print "Using toolchain from :" + ToolPath("", TOOLCHAIN_INFO)
129 return toolchain_info 132 return toolchain_info
130 133
131 raise Exception("Could not find tool chain") 134 raise Exception("Could not find tool chain")
132 135
136 def GetAapt():
137 """Returns the path to aapt.
138
139 Args:
140 None
141
142 Returns:
143 the pathname of the 'aapt' executable.
144 """
145 sdk_home = os.path.join('third_party', 'android_tools', 'sdk')
146 sdk_home = os.environ.get('SDK_HOME', sdk_home)
147 aapt_exe = glob.glob(os.path.join(sdk_home, 'build-tools', '*', 'aapt'))
148 if not aapt_exe:
149 return None
150 return sorted(aapt_exe, key=os.path.getmtime, reverse=True)[0]
151
152 def GetPackageName(aapt, apk_path):
153 """Returns the package name of the apk.
154
155 Args:
156 aapt: pathname for the 'aapt' executable.
157 apk_path: pathname of the APK file.
158
159 Returns:
160 the package name of the APK file.
161 """
162 if not aapt:
163 return None
rmcilroy 2014/07/21 16:05:31 return apk_path here for allowing false positives
anton1 2014/07/22 13:54:03 apk_path is not the same as the package_name so th
rmcilroy 2014/07/22 14:22:31 Ahh right. How about instead of GetPackageName yo
164 aapt_output = subprocess.check_output(
165 [aapt, 'dump', 'badging', apk_path]).split('\n')
166 package_name_re = re.compile(r'package: .*name=\'(\S*)\'')
167 for line in aapt_output:
168 m = package_name_re.match(line)
rmcilroy 2014/07/21 16:05:30 nit - more descriptive variable names than "m" and
anton1 2014/07/22 13:54:03 Done.
169 if m:
170 return m.group(1)
171
172 def GetCandidateApks():
173 """Returns a list of APKs which could contain the library.
174
175 Args:
176 None
177
178 Returns:
179 list of APK filename which could contain the library.
180 """
181 out_dir = os.environ.get('CHROMIUM_OUT_DIR', 'out')
182 buildtype = os.environ.get('BUILDTYPE')
183 if buildtype:
184 candidate_dirs = [os.path.join(out_dir, buildtype, 'apks')]
185 else:
186 candidate_dirs = [os.path.join(out_dir, 'Debug', 'apks'),
187 os.path.join(out_dir, 'Release', 'apks'),
188 ]
189 candidate_apks = list(itertools.chain.from_iterable(
190 map(lambda d: glob.glob(os.path.join(d, '*.apk')), candidate_dirs)))
191 candidate_apks = sorted(candidate_apks, key=os.path.getmtime, reverse=True)
192 return candidate_apks
rmcilroy 2014/07/21 16:05:30 Could you put MapDeviceApkToLibrary after L274 and
anton1 2014/07/22 13:54:03 The candidate_dirs at L274 are for "libs" at 184 t
rmcilroy 2014/07/22 14:22:31 As discussed offline, you could factor this out to
193
194 def GetCrazyLib(apk_filename):
195 """Returns the name of the first crazy library from this APK.
196
197 Args:
198 apk_filename: name of an APK file.
199
200 Returns:
201 Name of the first library which would be crazy loaded from this APK.
202 """
203 z = zipfile.ZipFile(apk_filename, 'r')
204 for filename in z.namelist():
205 m = re.match('lib/[^/]*/crazy.(lib.*[.]so)', filename)
206 if m:
207 return m.group(1)
208
209 def GetMatchingApks(device_apk_name):
210 """Find any APKs which match the package indicated by the device_apk_name.
211
212 Args:
213 device_apk_name: name of the APK on the device.
214
215 Returns:
216 a list of APK filenames which could contain the desired library.
rmcilroy 2014/07/21 16:05:32 /s/a/A
anton1 2014/07/22 13:54:03 Done.
217 """
218 m = re.match('(.*)-[0-9]+[.]apk$', device_apk_name)
219 if not m:
220 return None
221 package_name = m.group(1)
222 aapt = GetAapt()
223 if not aapt:
224 # Allow false positives
225 return GetCandidateApks()
226 candidate_apks = GetCandidateApks()
227 return filter(
228 lambda candidate_apk :
229 package_name == GetPackageName(aapt, candidate_apk),
rmcilroy 2014/07/21 16:05:30 indent (if you can)
anton1 2014/07/22 13:54:03 Done.
230 candidate_apks)
231
232 def MapDeviceApkToLibrary(device_apk_name):
233 """Provide a library name which corresponds with device_apk_name.
234
235 Args:
236 device_apk_name: name of the APK on the device.
237
238 Returns:
239 Name of the library which corresponds to that APK.
240 """
241 matching_apks = GetMatchingApks(device_apk_name)
242 for matching_apk in matching_apks:
243 crazy = GetCrazyLib(matching_apk)
rmcilroy 2014/07/21 16:05:32 nit - crazy_lib
anton1 2014/07/22 13:54:03 Done.
244 if crazy:
245 return crazy
246
133 def TranslateLibPath(lib): 247 def TranslateLibPath(lib):
134 # SymbolInformation(lib, addr) receives lib as the path from symbols 248 # SymbolInformation(lib, addr) receives lib as the path from symbols
135 # root to the symbols file. This needs to be translated to point to the 249 # root to the symbols file. This needs to be translated to point to the
136 # correct .so path. If the user doesn't explicitly specify which directory to 250 # correct .so path. If the user doesn't explicitly specify which directory to
137 # use, then use the most recently updated one in one of the known directories. 251 # use, then use the most recently updated one in one of the known directories.
138 # If the .so is not found somewhere in CHROME_SYMBOLS_DIR, leave it 252 # If the .so is not found somewhere in CHROME_SYMBOLS_DIR, leave it
139 # untranslated in case it is an Android symbol in SYMBOLS_DIR. 253 # untranslated in case it is an Android symbol in SYMBOLS_DIR.
140 library_name = os.path.basename(lib) 254 library_name = os.path.basename(lib)
255
256 if re.search('-[0-9]+[.]apk$', library_name):
rmcilroy 2014/07/21 16:05:32 Add a comment stating what you are doing here
anton1 2014/07/22 13:54:03 Done.
257 mapping = MapDeviceApkToLibrary(library_name)
258 if mapping:
259 library_name = mapping
260
141 out_dir = os.environ.get('CHROMIUM_OUT_DIR', 'out') 261 out_dir = os.environ.get('CHROMIUM_OUT_DIR', 'out')
142 candidate_dirs = ['.', 262 candidate_dirs = ['.',
143 os.path.join(out_dir, 'Debug', 'lib'), 263 os.path.join(out_dir, 'Debug', 'lib'),
144 os.path.join(out_dir, 'Debug', 'lib.target'), 264 os.path.join(out_dir, 'Debug', 'lib.target'),
145 os.path.join(out_dir, 'Release', 'lib'), 265 os.path.join(out_dir, 'Release', 'lib'),
146 os.path.join(out_dir, 'Release', 'lib.target'), 266 os.path.join(out_dir, 'Release', 'lib.target'),
147 ] 267 ]
148
149 candidate_libraries = map( 268 candidate_libraries = map(
150 lambda d: ('%s/%s/%s' % (CHROME_SYMBOLS_DIR, d, library_name)), 269 lambda d: ('%s/%s/%s' % (CHROME_SYMBOLS_DIR, d, library_name)),
151 candidate_dirs) 270 candidate_dirs)
152 candidate_libraries = filter(os.path.exists, candidate_libraries) 271 candidate_libraries = filter(os.path.exists, candidate_libraries)
153 candidate_libraries = sorted(candidate_libraries, 272 candidate_libraries = sorted(candidate_libraries,
154 key=os.path.getmtime, reverse=True) 273 key=os.path.getmtime, reverse=True)
155 274
156 if not candidate_libraries: 275 if not candidate_libraries:
157 return lib 276 return lib
158 277
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 process.stdin.write("\n") 533 process.stdin.write("\n")
415 process.stdin.close() 534 process.stdin.close()
416 demangled_symbol = process.stdout.readline().strip() 535 demangled_symbol = process.stdout.readline().strip()
417 process.stdout.close() 536 process.stdout.close()
418 return demangled_symbol 537 return demangled_symbol
419 538
420 def FormatSymbolWithOffset(symbol, offset): 539 def FormatSymbolWithOffset(symbol, offset):
421 if offset == 0: 540 if offset == 0:
422 return symbol 541 return symbol
423 return "%s+%d" % (symbol, offset) 542 return "%s+%d" % (symbol, offset)
OLDNEW
« no previous file with comments | « third_party/android_platform/README.chromium ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698