Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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) |
| OLD | NEW |