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