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