1import gdbremote_testcase
2from lldbsuite.test.decorators import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5
6
7class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
8
9    mydir = TestBase.compute_mydir(__file__)
10
11    AUXV_SUPPORT_FEATURE_NAME = "qXfer:auxv:read"
12
13    @skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet
14    def has_auxv_support(self):
15        inferior_args = ["message:main entered", "sleep:5"]
16        procs = self.prep_debug_monitor_and_inferior(
17            inferior_args=inferior_args)
18
19        # Don't do anything until we match the launched inferior main entry output.
20        # Then immediately interrupt the process.
21        # This prevents auxv data being asked for before it's ready and leaves
22        # us in a stopped state.
23        self.test_sequence.add_log_lines([
24            # Start the inferior...
25            "read packet: $c#63",
26            # ... match output....
27            {"type": "output_match", "regex": self.maybe_strict_output_regex(
28                r"message:main entered\r\n")},
29        ], True)
30        # ... then interrupt.
31        self.add_interrupt_packets()
32        self.add_qSupported_packets()
33
34        context = self.expect_gdbremote_sequence()
35        self.assertIsNotNone(context)
36
37        features = self.parse_qSupported_response(context)
38        return self.AUXV_SUPPORT_FEATURE_NAME in features and features[
39            self.AUXV_SUPPORT_FEATURE_NAME] == "+"
40
41    def get_raw_auxv_data(self):
42        # Start up llgs and inferior, and check for auxv support.
43        if not self.has_auxv_support():
44            self.skipTest("auxv data not supported")
45
46        # Grab pointer size for target.  We'll assume that is equivalent to an unsigned long on the target.
47        # Auxv is specified in terms of pairs of unsigned longs.
48        self.reset_test_sequence()
49        self.add_process_info_collection_packets()
50
51        context = self.expect_gdbremote_sequence()
52        self.assertIsNotNone(context)
53
54        proc_info = self.parse_process_info_response(context)
55        self.assertIsNotNone(proc_info)
56        self.assertTrue("ptrsize" in proc_info)
57        word_size = int(proc_info["ptrsize"])
58
59        OFFSET = 0
60        LENGTH = 0x400
61
62        # Grab the auxv data.
63        self.reset_test_sequence()
64        self.test_sequence.add_log_lines(
65            [
66                "read packet: $qXfer:auxv:read::{:x},{:x}:#00".format(
67                    OFFSET,
68                    LENGTH),
69                {
70                    "direction": "send",
71                    "regex": re.compile(
72                        r"^\$([^E])(.*)#[0-9a-fA-F]{2}$",
73                        re.MULTILINE | re.DOTALL),
74                    "capture": {
75                        1: "response_type",
76                        2: "content_raw"}}],
77            True)
78
79        context = self.expect_gdbremote_sequence()
80        self.assertIsNotNone(context)
81
82        # Ensure we end up with all auxv data in one packet.
83        # FIXME don't assume it all comes back in one packet.
84        self.assertEqual(context.get("response_type"), "l")
85
86        # Decode binary data.
87        content_raw = context.get("content_raw")
88        self.assertIsNotNone(content_raw)
89        return (word_size, self.decode_gdbremote_binary(content_raw))
90
91    def supports_auxv(self):
92        # When non-auxv platforms support llgs, skip the test on platforms
93        # that don't support auxv.
94        self.assertTrue(self.has_auxv_support())
95
96    #
97    # We skip the "supports_auxv" test on debugserver.  The rest of the tests
98    # appropriately skip the auxv tests if the support flag is not present
99    # in the qSupported response, so the debugserver test bits are still there
100    # in case debugserver code one day does have auxv support and thus those
101    # tests don't get skipped.
102    #
103
104    @skipIfWindows # no auxv support.
105    @llgs_test
106    def test_supports_auxv_llgs(self):
107        self.init_llgs_test()
108        self.build()
109        self.set_inferior_startup_launch()
110        self.supports_auxv()
111
112    def auxv_data_is_correct_size(self):
113        (word_size, auxv_data) = self.get_raw_auxv_data()
114        self.assertIsNotNone(auxv_data)
115
116        # Ensure auxv data is a multiple of 2*word_size (there should be two
117        # unsigned long fields per auxv entry).
118        self.assertEqual(len(auxv_data) % (2 * word_size), 0)
119        self.trace("auxv contains {} entries".format(len(auxv_data) / (2*word_size)))
120
121    @debugserver_test
122    def test_auxv_data_is_correct_size_debugserver(self):
123        self.init_debugserver_test()
124        self.build()
125        self.set_inferior_startup_launch()
126        self.auxv_data_is_correct_size()
127
128    @skipIfWindows
129    @expectedFailureNetBSD
130    @llgs_test
131    def test_auxv_data_is_correct_size_llgs(self):
132        self.init_llgs_test()
133        self.build()
134        self.set_inferior_startup_launch()
135        self.auxv_data_is_correct_size()
136
137    def auxv_keys_look_valid(self):
138        (word_size, auxv_data) = self.get_raw_auxv_data()
139        self.assertIsNotNone(auxv_data)
140
141        # Grab endian.
142        self.reset_test_sequence()
143        self.add_process_info_collection_packets()
144        context = self.expect_gdbremote_sequence()
145        self.assertIsNotNone(context)
146
147        process_info = self.parse_process_info_response(context)
148        self.assertIsNotNone(process_info)
149        endian = process_info.get("endian")
150        self.assertIsNotNone(endian)
151
152        auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data)
153        self.assertIsNotNone(auxv_dict)
154
155        # Verify keys look reasonable.
156        for auxv_key in auxv_dict:
157            self.assertTrue(auxv_key >= 1)
158            self.assertTrue(auxv_key <= 1000)
159        self.trace("auxv dict: {}".format(auxv_dict))
160
161    @debugserver_test
162    def test_auxv_keys_look_valid_debugserver(self):
163        self.init_debugserver_test()
164        self.build()
165        self.set_inferior_startup_launch()
166        self.auxv_keys_look_valid()
167
168    @skipIfWindows
169    @expectedFailureNetBSD
170    @llgs_test
171    def test_auxv_keys_look_valid_llgs(self):
172        self.init_llgs_test()
173        self.build()
174        self.set_inferior_startup_launch()
175        self.auxv_keys_look_valid()
176
177    def auxv_chunked_reads_work(self):
178        # Verify that multiple smaller offset,length reads of auxv data
179        # return the same data as a single larger read.
180
181        # Grab the auxv data with a single large read here.
182        (word_size, auxv_data) = self.get_raw_auxv_data()
183        self.assertIsNotNone(auxv_data)
184
185        # Grab endian.
186        self.reset_test_sequence()
187        self.add_process_info_collection_packets()
188        context = self.expect_gdbremote_sequence()
189        self.assertIsNotNone(context)
190
191        process_info = self.parse_process_info_response(context)
192        self.assertIsNotNone(process_info)
193        endian = process_info.get("endian")
194        self.assertIsNotNone(endian)
195
196        auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data)
197        self.assertIsNotNone(auxv_dict)
198
199        iterated_auxv_data = self.read_binary_data_in_chunks(
200            "qXfer:auxv:read::", 2 * word_size)
201        self.assertIsNotNone(iterated_auxv_data)
202
203        auxv_dict_iterated = self.build_auxv_dict(
204            endian, word_size, iterated_auxv_data)
205        self.assertIsNotNone(auxv_dict_iterated)
206
207        # Verify both types of data collection returned same content.
208        self.assertEqual(auxv_dict_iterated, auxv_dict)
209
210    @debugserver_test
211    def test_auxv_chunked_reads_work_debugserver(self):
212        self.init_debugserver_test()
213        self.build()
214        self.set_inferior_startup_launch()
215        self.auxv_chunked_reads_work()
216
217    @skipIfWindows
218    @expectedFailureNetBSD
219    @llgs_test
220    def test_auxv_chunked_reads_work_llgs(self):
221        self.init_llgs_test()
222        self.build()
223        self.set_inferior_startup_launch()
224        self.auxv_chunked_reads_work()
225