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