1""" This module contains functions used by the test cases to hide the 2architecture and/or the platform dependent nature of the tests. """ 3 4# System modules 5import itertools 6import re 7import subprocess 8import sys 9import os 10from distutils.version import LooseVersion 11from urllib.parse import urlparse 12 13# LLDB modules 14import lldb 15from . import configuration 16from . import lldbtest_config 17import lldbsuite.test.lldbplatform as lldbplatform 18from lldbsuite.test.builders import get_builder 19 20 21def check_first_register_readable(test_case): 22 arch = test_case.getArchitecture() 23 24 if arch in ["x86_64", "i386"]: 25 test_case.expect("register read eax", substrs=["eax = 0x"]) 26 elif arch in ["arm", "armv7", "armv7k", "armv8l", "armv7l"]: 27 test_case.expect("register read r0", substrs=["r0 = 0x"]) 28 elif arch in ["aarch64", "arm64", "arm64e", "arm64_32"]: 29 test_case.expect("register read x0", substrs=["x0 = 0x"]) 30 elif re.match("mips", arch): 31 test_case.expect("register read zero", substrs=["zero = 0x"]) 32 elif arch in ["s390x"]: 33 test_case.expect("register read r0", substrs=["r0 = 0x"]) 34 elif arch in ["powerpc64le"]: 35 test_case.expect("register read r0", substrs=["r0 = 0x"]) 36 else: 37 # TODO: Add check for other architectures 38 test_case.fail( 39 "Unsupported architecture for test case (arch: %s)" 40 % test_case.getArchitecture() 41 ) 42 43 44def _run_adb_command(cmd, device_id): 45 device_id_args = [] 46 if device_id: 47 device_id_args = ["-s", device_id] 48 full_cmd = ["adb"] + device_id_args + cmd 49 p = subprocess.Popen(full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 50 stdout, stderr = p.communicate() 51 return p.returncode, stdout, stderr 52 53 54def target_is_android(): 55 return configuration.lldb_platform_name == "remote-android" 56 57 58def android_device_api(): 59 if not hasattr(android_device_api, "result"): 60 assert configuration.lldb_platform_url is not None 61 device_id = None 62 parsed_url = urlparse(configuration.lldb_platform_url) 63 host_name = parsed_url.netloc.split(":")[0] 64 if host_name != "localhost": 65 device_id = host_name 66 if device_id.startswith("[") and device_id.endswith("]"): 67 device_id = device_id[1:-1] 68 retcode, stdout, stderr = _run_adb_command( 69 ["shell", "getprop", "ro.build.version.sdk"], device_id 70 ) 71 if retcode == 0: 72 android_device_api.result = int(stdout) 73 else: 74 raise LookupError( 75 ">>> Unable to determine the API level of the Android device.\n" 76 ">>> stdout:\n%s\n" 77 ">>> stderr:\n%s\n" % (stdout, stderr) 78 ) 79 return android_device_api.result 80 81 82def match_android_device(device_arch, valid_archs=None, valid_api_levels=None): 83 if not target_is_android(): 84 return False 85 if valid_archs is not None and device_arch not in valid_archs: 86 return False 87 if valid_api_levels is not None and android_device_api() not in valid_api_levels: 88 return False 89 90 return True 91 92 93def finalize_build_dictionary(dictionary): 94 if target_is_android(): 95 if dictionary is None: 96 dictionary = {} 97 dictionary["OS"] = "Android" 98 dictionary["PIE"] = 1 99 return dictionary 100 101 102def _get_platform_os(p): 103 # Use the triple to determine the platform if set. 104 triple = p.GetTriple() 105 if triple: 106 platform = triple.split("-")[2] 107 if platform.startswith("freebsd"): 108 platform = "freebsd" 109 elif platform.startswith("netbsd"): 110 platform = "netbsd" 111 elif platform.startswith("openbsd"): 112 platform = "openbsd" 113 return platform 114 115 return "" 116 117 118def getHostPlatform(): 119 """Returns the host platform running the test suite.""" 120 return _get_platform_os(lldb.SBPlatform("host")) 121 122 123def getDarwinOSTriples(): 124 return lldbplatform.translate(lldbplatform.darwin_all) 125 126 127def getPlatform(): 128 """Returns the target platform which the tests are running on.""" 129 # Use the Apple SDK to determine the platform if set. 130 if configuration.apple_sdk: 131 platform = configuration.apple_sdk 132 dot = platform.find(".") 133 if dot != -1: 134 platform = platform[:dot] 135 if platform == "iphoneos": 136 platform = "ios" 137 return platform 138 139 return _get_platform_os(lldb.selected_platform) 140 141 142def platformIsDarwin(): 143 """Returns true if the OS triple for the selected platform is any valid apple OS""" 144 return getPlatform() in getDarwinOSTriples() 145 146 147def findMainThreadCheckerDylib(): 148 if not platformIsDarwin(): 149 return "" 150 151 if getPlatform() in lldbplatform.translate(lldbplatform.darwin_embedded): 152 return "/Developer/usr/lib/libMainThreadChecker.dylib" 153 154 with os.popen("xcode-select -p") as output: 155 xcode_developer_path = output.read().strip() 156 mtc_dylib_path = "%s/usr/lib/libMainThreadChecker.dylib" % xcode_developer_path 157 if os.path.isfile(mtc_dylib_path): 158 return mtc_dylib_path 159 160 return "" 161 162 163class _PlatformContext(object): 164 """Value object class which contains platform-specific options.""" 165 166 def __init__( 167 self, shlib_environment_var, shlib_path_separator, shlib_prefix, shlib_extension 168 ): 169 self.shlib_environment_var = shlib_environment_var 170 self.shlib_path_separator = shlib_path_separator 171 self.shlib_prefix = shlib_prefix 172 self.shlib_extension = shlib_extension 173 174 175def createPlatformContext(): 176 if platformIsDarwin(): 177 return _PlatformContext("DYLD_LIBRARY_PATH", ":", "lib", "dylib") 178 elif getPlatform() in ("linux", "freebsd", "netbsd", "openbsd"): 179 return _PlatformContext("LD_LIBRARY_PATH", ":", "lib", "so") 180 else: 181 return _PlatformContext("PATH", ";", "", "dll") 182 183 184def hasChattyStderr(test_case): 185 """Some targets produce garbage on the standard error output. This utility function 186 determines whether the tests can be strict about the expected stderr contents.""" 187 if match_android_device( 188 test_case.getArchitecture(), ["aarch64"], range(22, 25 + 1) 189 ): 190 return True # The dynamic linker on the device will complain about unknown DT entries 191 return False 192 193 194def builder_module(): 195 return get_builder(sys.platform) 196 197 198def getArchitecture(): 199 """Returns the architecture in effect the test suite is running with.""" 200 module = builder_module() 201 arch = module.getArchitecture() 202 if arch == "amd64": 203 arch = "x86_64" 204 if arch in ["armv7l", "armv8l"]: 205 arch = "arm" 206 return arch 207 208 209lldbArchitecture = None 210 211 212def getLLDBArchitecture(): 213 """Returns the architecture of the lldb binary.""" 214 global lldbArchitecture 215 if not lldbArchitecture: 216 # These two target settings prevent lldb from doing setup that does 217 # nothing but slow down the end goal of printing the architecture. 218 command = [ 219 lldbtest_config.lldbExec, 220 "-x", 221 "-b", 222 "-o", 223 "settings set target.preload-symbols false", 224 "-o", 225 "settings set target.load-script-from-symbol-file false", 226 "-o", 227 "file " + lldbtest_config.lldbExec, 228 ] 229 230 output = subprocess.check_output(command) 231 str = output.decode() 232 233 for line in str.splitlines(): 234 m = re.search(r"Current executable set to '.*' \((.*)\)\.", line) 235 if m: 236 lldbArchitecture = m.group(1) 237 break 238 239 return lldbArchitecture 240 241 242def getCompiler(): 243 """Returns the compiler in effect the test suite is running with.""" 244 module = builder_module() 245 return module.getCompiler() 246 247 248def getCompilerBinary(): 249 """Returns the compiler binary the test suite is running with.""" 250 return getCompiler().split()[0] 251 252 253def getCompilerVersion(): 254 """Returns a string that represents the compiler version. 255 Supports: llvm, clang. 256 """ 257 compiler = getCompilerBinary() 258 version_output = subprocess.check_output([compiler, "--version"], errors="replace") 259 m = re.search("version ([0-9.]+)", version_output) 260 if m: 261 return m.group(1) 262 return "unknown" 263 264 265def getDwarfVersion(): 266 """Returns the dwarf version generated by clang or '0'.""" 267 if configuration.dwarf_version: 268 return str(configuration.dwarf_version) 269 if "clang" in getCompiler(): 270 try: 271 triple = builder_module().getTriple(getArchitecture()) 272 target = ["-target", triple] if triple else [] 273 driver_output = subprocess.check_output( 274 [getCompiler()] + target + "-g -c -x c - -o - -###".split(), 275 stderr=subprocess.STDOUT, 276 ) 277 driver_output = driver_output.decode("utf-8") 278 for line in driver_output.split(os.linesep): 279 m = re.search("dwarf-version=([0-9])", line) 280 if m: 281 return m.group(1) 282 except subprocess.CalledProcessError: 283 pass 284 return "0" 285 286 287def expectedCompilerVersion(compiler_version): 288 """Returns True iff compiler_version[1] matches the current compiler version. 289 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 290 Any operator other than the following defaults to an equality test: 291 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 292 293 If the current compiler version cannot be determined, we assume it is close to the top 294 of trunk, so any less-than or equal-to comparisons will return False, and any 295 greater-than or not-equal-to comparisons will return True. 296 """ 297 if compiler_version is None: 298 return True 299 operator = str(compiler_version[0]) 300 version = compiler_version[1] 301 302 if version is None: 303 return True 304 305 test_compiler_version = getCompilerVersion() 306 if test_compiler_version == "unknown": 307 # Assume the compiler version is at or near the top of trunk. 308 return operator in [">", ">=", "!", "!=", "not"] 309 310 if operator == ">": 311 return LooseVersion(test_compiler_version) > LooseVersion(version) 312 if operator == ">=" or operator == "=>": 313 return LooseVersion(test_compiler_version) >= LooseVersion(version) 314 if operator == "<": 315 return LooseVersion(test_compiler_version) < LooseVersion(version) 316 if operator == "<=" or operator == "=<": 317 return LooseVersion(test_compiler_version) <= LooseVersion(version) 318 if operator == "!=" or operator == "!" or operator == "not": 319 return str(version) not in str(test_compiler_version) 320 return str(version) in str(test_compiler_version) 321 322 323def expectedCompiler(compilers): 324 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 325 if compilers is None: 326 return True 327 328 for compiler in compilers: 329 if compiler in getCompiler(): 330 return True 331 332 return False 333