Index: test/functionalities/load_unload/Makefile =================================================================== --- test/functionalities/load_unload/Makefile +++ test/functionalities/load_unload/Makefile @@ -43,8 +43,8 @@ main.o: main.c $(CC) $(CFLAGS) -c main.c -hidden/$(LIB_D): b.o - $(CC) $(CFLAGS) $(LD_FLAGS) -o hidden/$(LIB_D) d.o +hidden/$(LIB_D): dh.o + $(CC) $(CFLAGS) $(LD_FLAGS) -o hidden/$(LIB_D) dh.o if [ "$(OS)" = "Darwin" ]; then dsymutil -o hidden/$(LIB_D).dSYM hidden/$(LIB_D); fi $(LIB_A): a.o $(LIB_B) @@ -75,5 +75,8 @@ d.o: d.c $(CC) $(CFLAGS) -c d.c +dh.o: d.c + $(CC) $(CFLAGS) -DHIDDEN -c d.c -o dh.o + clean: rm -rf $(wildcard *.o *~ *.dylib *.so a.out *.dSYM hidden/*) Index: test/functionalities/load_unload/TestLoadUnload.py =================================================================== --- test/functionalities/load_unload/TestLoadUnload.py +++ test/functionalities/load_unload/TestLoadUnload.py @@ -25,10 +25,44 @@ self.line_d_function = line_number('d.c', '// Find this line number within d_dunction().') if not self.platformIsDarwin(): - if "LD_LIBRARY_PATH" in os.environ: + if not lldb.remote_platform and "LD_LIBRARY_PATH" in os.environ: self.runCmd("settings set target.env-vars " + self.dylibPath + "=" + os.environ["LD_LIBRARY_PATH"] + ":" + os.getcwd()) else: - self.runCmd("settings set target.env-vars " + self.dylibPath + "=" + os.getcwd()) + if lldb.remote_platform: + wd = lldb.remote_platform.GetWorkingDirectory() + else: + wd = os.getcwd() + self.runCmd("settings set target.env-vars " + self.dylibPath + "=" + wd) + + def copy_shlibs_to_remote(self, hidden_dir=False): + """ Copies the shared libs required by this test suite to remote. + Does nothing in case of non-remote platforms. + """ + if lldb.remote_platform: + triple = lldb.remote_platform.GetTriple() + cwd = os.getcwd() + if 'android' in triple: + shlibs = ['libloadunload_a.so', 'libloadunload_b.so', + 'libloadunload_c.so', 'libloadunload_d.so'] + wd = lldb.remote_platform.GetWorkingDirectory() + for f in shlibs: + lldbutil.push_file_to_android_device( + os.path.join(cwd, f), wd) + if hidden_dir: + hidden_dir = os.path.join(wd, 'hidden') + r, stdout, stderr = lldbutil.run_adb_command( + ['shell', 'mkdir', hidden_dir], + lldbutil.android_device_id()) + if r != 0: + raise RuntimeError( + "Unable to create '%s' directory." % hidden_dir) + lldbutil.push_file_to_android_device( + os.path.join(cwd, 'hidden', 'libloadunload_d.so'), + hidden_dir) + else: + raise NotImplementedError( + "Copying files to remote platform '%s' not implemented" % + triple) @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support @not_remote_testsuite_ready @@ -83,12 +117,13 @@ substrs = [new_dylib]) @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support - @not_remote_testsuite_ready + @skipIfUnlistedRemote(['android']) def test_dyld_library_path(self): """Test (DY)LD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else.""" # Invoke the default build rule. self.buildDefault() + self.copy_shlibs_to_remote(hidden_dir=True) exe = os.path.join(os.getcwd(), "a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -101,19 +136,22 @@ # The directory to relocate the dynamic library and its debugging info. special_dir = "hidden" - new_dir = os.path.join(os.getcwd(), special_dir) + if lldb.remote_platform: + wd = lldb.remote_platform.GetWorkingDirectory() + else: + wd = os.getcwd() - old_dylib = os.path.join(os.getcwd(), dylibName) - new_dylib = os.path.join(new_dir, dylibName) + old_dir = wd + new_dir = os.path.join(wd, special_dir) + old_dylib = os.path.join(old_dir, dylibName) #system(["ls", "-lR", "."]) # Try running with the (DY)LD_LIBRARY_PATH environment variable set, make sure # we pick up the hidden dylib. - env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir - if not self.platformIsDarwin(): - env_cmd_string += ":" + os.getcwd() + env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + wd + self.runCmd(env_cmd_string) if self.TraceOn(): print "Set environment to: ", env_cmd_string @@ -135,19 +173,35 @@ self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, patterns = ["frame #0.*d_function.*at d.c:%d" % self.line_d_function]) - # After run, make sure the hidden library is present, and the one we didn't - # load is not. - self.expect("target modules list", - substrs = [special_dir, os.path.basename(new_dylib)]) + # After run, make sure the non-hidden library is picked up. + self.expect("finish", substrs=["Return value", "700"]) + + self.runCmd("continue") + + # Remove the hidden directory from search path. + env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir + if not self.platformIsDarwin(): + env_cmd_string += ":" + wd + self.runCmd(env_cmd_string) + + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + lldbutil.run_break_set_by_file_and_line (self, "d.c", self.line_d_function, num_expected_locations=1, loc_exact=True) + self.runCmd("run") + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + patterns = ["frame #0.*d_function.*at d.c:%d" % self.line_d_function]) + + # This time, the hidden library should be picked up. + self.expect("finish", substrs=["Return value", "700"]) @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support - @not_remote_testsuite_ready + @skipIfUnlistedRemote(['android']) @unittest2.expectedFailure("rdar://15367406") def test_lldb_process_load_and_unload_commands(self): """Test that lldb process load/unload command work correctly.""" # Invoke the default build rule. self.buildDefault() + self.copy_shlibs_to_remote() exe = os.path.join(os.getcwd(), "a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -159,12 +213,18 @@ self.runCmd("run", RUN_FAILED) + if lldb.remote_platform: + shlib_dir = lldb.remote_platform.GetWorkingDirectory() + else: + shlib_dir = self.mydir # Make sure that a_function does not exist at this point. self.expect("image lookup -n a_function", "a_function should not exist yet", error=True, matching=False, - patterns = ["1 match found .* %s" % self.mydir]) + patterns = ["1 match found .* %s" % shlib_dir]) - if self.platformIsDarwin(): + if lldb.remote_platform: + dylibName = os.path.join(shlib_dir, 'libloadunload_a.so') + elif self.platformIsDarwin(): dylibName = 'libloadunload_a.dylib' else: dylibName = 'libloadunload_a.so' @@ -186,7 +246,7 @@ # Now we should have an entry for a_function. self.expect("image lookup -n a_function", "a_function should now exist", - patterns = ["1 match found .*%s" % self.mydir]) + patterns = ["1 match found .*%s" % shlib_dir]) # Use lldb 'process unload' to unload the dylib. self.expect("process unload %s" % index, "%s unloaded correctly" % dylibName, @@ -195,12 +255,13 @@ self.runCmd("process continue") @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support - @not_remote_testsuite_ready + @skipIfUnlistedRemote(['android']) def test_load_unload(self): """Test breakpoint by name works correctly with dlopen'ing.""" # Invoke the default build rule. self.buildDefault() + self.copy_shlibs_to_remote() exe = os.path.join(os.getcwd(), "a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -236,12 +297,13 @@ substrs = [' resolved, hit count = 2']) @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support - @not_remote_testsuite_ready + @skipIfUnlistedRemote(['android']) def test_step_over_load (self): """Test stepping over code that loads a shared library works correctly.""" # Invoke the default build rule. self.buildDefault() + self.copy_shlibs_to_remote() exe = os.path.join(os.getcwd(), "a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) Index: test/functionalities/load_unload/d.c =================================================================== --- test/functionalities/load_unload/d.c +++ test/functionalities/load_unload/d.c @@ -9,5 +9,9 @@ int d_function () { +#ifdef HIDDEN + return 12345; +#else return 700; // Find this line number within d_dunction(). +#endif } Index: test/lldbtest.py =================================================================== --- test/lldbtest.py +++ test/lldbtest.py @@ -47,11 +47,6 @@ import lldbutil from _pyio import __metaclass__ -if sys.version_info.major < 3: - import urlparse -else: - import urllib.parse as urlparse - # dosep.py starts lots and lots of dotest instances # This option helps you find if two (or more) dotest instances are using the same # directory at the same time @@ -434,31 +429,6 @@ return __import__("builder_freebsd") return __import__("builder_" + sys.platform) -def run_adb_command(cmd, device_id): - device_id_args = [] - if device_id: - device_id_args = ["-s", device_id] - full_cmd = ["adb"] + device_id_args + cmd - p = Popen(full_cmd, stdout=PIPE, stderr=PIPE) - stdout, stderr = p.communicate() - return p.returncode, stdout, stderr - -def android_device_api(): - assert lldb.platform_url is not None - device_id = None - parsed_url = urlparse.urlparse(lldb.platform_url) - if parsed_url.scheme == "adb": - device_id = parsed_url.netloc.split(":")[0] - retcode, stdout, stderr = run_adb_command( - ["shell", "getprop", "ro.build.version.sdk"], device_id) - if retcode == 0: - return int(stdout) - else: - raise LookupError( - ">>> Unable to determine the API level of the Android device.\n" - ">>> stdout:\n%s\n" - ">>> stderr:\n%s\n" % (stdout, stderr)) - # # Decorators for categorizing test cases. # @@ -707,7 +677,7 @@ if match: if not api_levels: return True - device_api = android_device_api() + device_api = lldbutil.android_device_api() return device_api and (device_api in api_levels) return expectedFailure(fn, bugnumber) @@ -735,6 +705,26 @@ func(*args, **kwargs) return wrapper +def skipIfUnlistedRemote(remote_list=None): + def myImpl(func): + if isinstance(func, type) and issubclass(func, unittest2.TestCase): + raise Exception("@skipIfRemote can only be used to decorate a test method") + + @wraps(func) + def wrapper(*args, **kwargs): + if remote_list and lldb.remote_platform: + self = args[0] + triple = self.dbg.GetSelectedPlatform().GetTriple() + for r in remote_list: + if r in triple: + func(*args, **kwargs) + return + self.skipTest("skip on remote platform %s" % str(triple)) + func(*args, **kwargs) + return wrapper + + return myImpl + def skipIfRemoteDueToDeadlock(func): """Decorate the item to skip tests if testing remotely due to the test deadlocking.""" if isinstance(func, type) and issubclass(func, unittest2.TestCase): @@ -971,7 +961,7 @@ triple = self.dbg.GetSelectedPlatform().GetTriple() if re.match(".*-.*-.*-android", triple): if api_levels: - device_api = android_device_api() + device_api = lldbutil.android_device_api() if device_api and (device_api in api_levels): self.skipTest( "skip on Android target with API %d" % device_api) Index: test/lldbutil.py =================================================================== --- test/lldbutil.py +++ test/lldbutil.py @@ -5,9 +5,56 @@ """ import lldb -import os, sys +import os +import subprocess +import sys import StringIO +if sys.version_info.major < 3: + import urlparse +else: + import urllib.parse as urlparse + +# =================================================== +# Utilities for working with Android devices +# =================================================== + +def run_adb_command(cmd, device_id): + device_id_args = [] + if device_id: + device_id_args = ["-s", device_id] + full_cmd = ["adb"] + device_id_args + cmd + p = subprocess.Popen( + full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + return p.returncode, stdout, stderr + +def android_device_id(): + assert lldb.platform_url is not None + parsed_url = urlparse.urlparse(lldb.platform_url) + if parsed_url.scheme == "adb": + return parsed_url.netloc.split(":")[0] + +def android_device_api(): + retcode, stdout, stderr = run_adb_command( + ["shell", "getprop", "ro.build.version.sdk"], android_device_id()) + if retcode == 0: + return int(stdout) + else: + raise LookupError( + ">>> Unable to determine the API level of the Android device.\n" + ">>> stdout:\n%s\n" + ">>> stderr:\n%s\n" % (stdout, stderr)) + +def push_file_to_android_device(src, dst): + retcode, stdout, stderr = run_adb_command( + ['push', src, dst], android_device_id()) + if retcode != 0: + raise RuntimeError( + ">>> Unable to push file '%s' to Android device path '%s'.\n" + ">>> stdout:\n%s\n" + ">>> stderr:\n%s\n" % (src, dst, stdout, stderr)) + # =================================================== # Utilities for locating/checking executable programs # ===================================================