1import xml.etree.ElementTree as ET
2
3import gdbremote_testcase
4from lldbsuite.test.decorators import *
5from lldbsuite.test.lldbtest import *
6
7
8class TestGdbRemoteLibrariesSvr4Support(gdbremote_testcase.GdbRemoteTestCaseBase):
9
10    mydir = TestBase.compute_mydir(__file__)
11
12    FEATURE_NAME = "qXfer:libraries-svr4:read"
13
14    def setup_test(self):
15        self.init_llgs_test()
16        self.build()
17        self.set_inferior_startup_launch()
18        env = {}
19        env[self.dylibPath] = self.getBuildDir()
20        self.prep_debug_monitor_and_inferior(inferior_env=env)
21        self.continue_process_and_wait_for_stop()
22
23    def get_expected_libs(self):
24        return ["libsvr4lib_a.so", 'libsvr4lib_b".so']
25
26    def has_libraries_svr4_support(self):
27        self.add_qSupported_packets()
28        context = self.expect_gdbremote_sequence()
29        self.assertIsNotNone(context)
30        features = self.parse_qSupported_response(context)
31        return self.FEATURE_NAME in features and features[self.FEATURE_NAME] == "+"
32
33    def get_libraries_svr4_data(self):
34        # Start up llgs and inferior, and check for libraries-svr4 support.
35        if not self.has_libraries_svr4_support():
36            self.skipTest("libraries-svr4 not supported")
37
38        # Grab the libraries-svr4 data.
39        self.reset_test_sequence()
40        self.test_sequence.add_log_lines(
41            [
42                "read packet: $qXfer:libraries-svr4:read::0,ffff:#00",
43                {
44                    "direction": "send",
45                    "regex": re.compile(
46                        r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL
47                    ),
48                    "capture": {1: "response_type", 2: "content_raw"},
49                },
50            ],
51            True,
52        )
53
54        context = self.expect_gdbremote_sequence()
55        self.assertIsNotNone(context)
56
57        # Ensure we end up with all libraries-svr4 data in one packet.
58        self.assertEqual(context.get("response_type"), "l")
59
60        # Decode binary data.
61        content_raw = context.get("content_raw")
62        self.assertIsNotNone(content_raw)
63        return content_raw
64
65    def get_libraries_svr4_xml(self):
66        libraries_svr4 = self.get_libraries_svr4_data()
67        xml_root = None
68        try:
69            xml_root = ET.fromstring(libraries_svr4)
70        except xml.etree.ElementTree.ParseError:
71            pass
72        self.assertIsNotNone(xml_root, "Malformed libraries-svr4 XML")
73        return xml_root
74
75    def libraries_svr4_well_formed(self):
76        xml_root = self.get_libraries_svr4_xml()
77        self.assertEqual(xml_root.tag, "library-list-svr4")
78        for child in xml_root:
79            self.assertEqual(child.tag, "library")
80            self.assertItemsEqual(child.attrib.keys(), ["name", "lm", "l_addr", "l_ld"])
81
82    def libraries_svr4_has_correct_load_addr(self):
83        xml_root = self.get_libraries_svr4_xml()
84        for child in xml_root:
85            name = child.attrib.get("name")
86            base_name = os.path.basename(name)
87            if os.path.basename(name) not in self.get_expected_libs():
88                continue
89            load_addr = int(child.attrib.get("l_addr"), 16)
90            self.reset_test_sequence()
91            self.add_query_memory_region_packets(load_addr)
92            context = self.expect_gdbremote_sequence()
93            mem_region = self.parse_memory_region_packet(context)
94            self.assertEqual(load_addr, int(mem_region.get("start", 0), 16))
95            self.assertEqual(
96                os.path.realpath(name), os.path.realpath(mem_region.get("name", ""))
97            )
98
99    def libraries_svr4_libs_present(self):
100        xml_root = self.get_libraries_svr4_xml()
101        libraries_svr4_names = []
102        for child in xml_root:
103            name = child.attrib.get("name")
104            libraries_svr4_names.append(os.path.realpath(name))
105        for lib in self.get_expected_libs():
106            self.assertIn(os.path.realpath(self.getBuildDir() + "/" + lib), libraries_svr4_names)
107
108    @llgs_test
109    @skipUnlessPlatform(["linux", "android", "freebsd", "netbsd"])
110    def test_supports_libraries_svr4(self):
111        self.setup_test()
112        self.assertTrue(self.has_libraries_svr4_support())
113
114    @llgs_test
115    @skipUnlessPlatform(["linux", "android", "freebsd", "netbsd"])
116    @expectedFailureNetBSD
117    def test_libraries_svr4_well_formed(self):
118        self.setup_test()
119        self.libraries_svr4_well_formed()
120
121    @llgs_test
122    @skipUnlessPlatform(["linux", "android", "freebsd", "netbsd"])
123    @expectedFailureAll(oslist=["freebsd", "netbsd"])
124    def test_libraries_svr4_load_addr(self):
125        self.setup_test()
126        self.libraries_svr4_has_correct_load_addr()
127
128    @llgs_test
129    @skipUnlessPlatform(["linux", "android", "freebsd", "netbsd"])
130    @expectedFailureNetBSD
131    def test_libraries_svr4_libs_present(self):
132        self.setup_test()
133        self.libraries_svr4_libs_present()
134