Get the shared cache filepath and uuid that the inferior process is using from debugserver, try to open that shared cache on the lldb host mac and if the UUID matches, index all of the binaries in that shared cache. When looking for binaries loaded in the process, get them from the already-indexed shared cache. Every time a binary is loaded, PlatformMacOSX may query the shared cache filepath and uuid from the Process, and pass that to HostInfo::GetSharedCacheImageInfo() if available (else fall back to the old HostInfo::GetSharedCacheImageInfo method which only looks at lldb's own shared cache), to get the file being requested. ProcessGDBRemote caches the shared cache filepath and uuid from the inferior, once it has a non-zero UUID. I added a lock for this ivar specifically, so I don't have 20 threads all asking for the shared cache information from debugserver and updating the cached answer. If we never get back a non-zero UUID shared cache reply, we will re-query at every library loaded notification. debugserver has been providing the shared cache UUID since 2013, although I only added the shared cache filepath field last November. Note that a process will not report its shared cache filepath or uuid at initial launch. As dyld gets a chance to execute a bit, it will start returning binaries -- it will be available at the point when libraries start loading. (it won't be available yet when the binary & dyld are the only two binaries loaded in the process) I tested this by disabling lldb's scan of its own shared cache pre-execution -- only loading the system shared cache when the inferior process reports that it is using that. I got 6-7 additional testsuite failures running lldb like that, because no system binaries were loaded before exeuction start, and the tests assumed they would be. rdar://148939795 --------- Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
"""
|
|
Test some lldb platform commands.
|
|
"""
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
|
|
class PlatformCommandTestCase(TestBase):
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
@no_debug_info_test
|
|
def test_help_platform(self):
|
|
self.runCmd("help platform")
|
|
|
|
@no_debug_info_test
|
|
def test_help_shell_alias(self):
|
|
self.expect(
|
|
"help shell",
|
|
substrs=[
|
|
"Run a shell command on the host.",
|
|
"shell <shell-command>",
|
|
"'shell' is an abbreviation",
|
|
],
|
|
)
|
|
# "platform shell" has options. The "shell" alias for it does not.
|
|
self.expect("help shell", substrs=["Command Options:"], matching=False)
|
|
|
|
@no_debug_info_test
|
|
def test_list(self):
|
|
self.expect("platform list", patterns=["^Available platforms:"])
|
|
|
|
@no_debug_info_test
|
|
def test_process_list(self):
|
|
self.expect("platform process list", substrs=["PID", "TRIPLE", "NAME"])
|
|
|
|
@no_debug_info_test
|
|
def test_process_info_with_no_arg(self):
|
|
"""This is expected to fail and to return a proper error message."""
|
|
self.expect(
|
|
"platform process info",
|
|
error=True,
|
|
substrs=["one or more process id(s) must be specified"],
|
|
)
|
|
|
|
@no_debug_info_test
|
|
def test_status(self):
|
|
self.expect(
|
|
"platform status",
|
|
substrs=[
|
|
"Platform",
|
|
"Triple",
|
|
"OS Version",
|
|
"Hostname",
|
|
"Kernel",
|
|
],
|
|
)
|
|
|
|
@expectedFailureAll(oslist=["windows"])
|
|
@no_debug_info_test
|
|
def test_shell(self):
|
|
"""Test that the platform shell command can invoke ls."""
|
|
triple = self.dbg.GetSelectedPlatform().GetTriple()
|
|
if re.match(".*-.*-windows", triple):
|
|
self.expect("platform shell dir c:\\", substrs=["Windows", "Program Files"])
|
|
self.expect("shell dir c:\\", substrs=["Windows", "Program Files"])
|
|
elif re.match(".*-.*-.*-android", triple):
|
|
self.expect("platform shell ls /", substrs=["cache", "dev", "system"])
|
|
self.expect("shell ls /", substrs=["cache", "dev", "system"])
|
|
else:
|
|
self.expect(
|
|
"platform shell ls /", substrs=["dev", "tmp", "usr"], ordered=False
|
|
)
|
|
self.expect("shell ls /", substrs=["dev", "tmp", "usr"], ordered=False)
|
|
|
|
@no_debug_info_test
|
|
def test_shell_builtin(self):
|
|
"""Test a shell built-in command (echo)"""
|
|
self.expect("platform shell echo hello lldb", substrs=["hello lldb"])
|
|
self.expect("shell echo hello lldb", substrs=["hello lldb"])
|
|
|
|
@no_debug_info_test
|
|
def test_shell_timeout(self):
|
|
"""Test a shell built-in command (sleep) that times out"""
|
|
self.skipTest("Alias with option not supported by the command interpreter.")
|
|
self.expect(
|
|
"platform shell -t 1 -- sleep 15",
|
|
error=True,
|
|
substrs=["error: timed out waiting for shell command to complete"],
|
|
)
|
|
self.expect(
|
|
"shell -t 1 -- sleep 3",
|
|
error=True,
|
|
substrs=["error: timed out waiting for shell command to complete"],
|
|
)
|
|
|
|
@no_debug_info_test
|
|
@skipIfRemote
|
|
def test_host_shell_interpreter(self):
|
|
"""Test the host platform shell with a different interpreter"""
|
|
self.build()
|
|
exe = self.getBuildArtifact("a.out")
|
|
self.expect(
|
|
"platform shell -h -s " + exe + " -- 'echo $0'",
|
|
substrs=["SUCCESS", "a.out"],
|
|
)
|