1import gdbremote_testcase
2from lldbsuite.test.decorators import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5
6class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase):
7
8    AUXV_SUPPORT_FEATURE_NAME = "qXfer:auxv:read"
9
10    def has_auxv_support(self):
11        procs = self.prep_debug_monitor_and_inferior()
12
13        self.add_qSupported_packets()
14        context = self.expect_gdbremote_sequence()
15        self.assertIsNotNone(context)
16
17        features = self.parse_qSupported_response(context)
18        return self.AUXV_SUPPORT_FEATURE_NAME in features and features[
19            self.AUXV_SUPPORT_FEATURE_NAME] == "+"
20
21    def get_raw_auxv_data(self):
22        # Start up llgs and inferior, and check for auxv support.
23        if not self.has_auxv_support():
24            self.skipTest("auxv data not supported")
25
26        # Grab pointer size for target.  We'll assume that is equivalent to an unsigned long on the target.
27        # Auxv is specified in terms of pairs of unsigned longs.
28        self.reset_test_sequence()
29        self.add_process_info_collection_packets()
30
31        context = self.expect_gdbremote_sequence()
32        self.assertIsNotNone(context)
33
34        proc_info = self.parse_process_info_response(context)
35        self.assertIsNotNone(proc_info)
36        self.assertIn("ptrsize", proc_info)
37        word_size = int(proc_info["ptrsize"])
38
39        OFFSET = 0
40        LENGTH = 0x400
41
42        # Grab the auxv data.
43        self.reset_test_sequence()
44        self.test_sequence.add_log_lines(
45            [
46                "read packet: $qXfer:auxv:read::{:x},{:x}:#00".format(
47                    OFFSET,
48                    LENGTH),
49                {
50                    "direction": "send",
51                    "regex": re.compile(
52                        r"^\$([^E])(.*)#[0-9a-fA-F]{2}$",
53                        re.MULTILINE | re.DOTALL),
54                    "capture": {
55                        1: "response_type",
56                        2: "content_raw"}}],
57            True)
58
59        context = self.expect_gdbremote_sequence()
60        self.assertIsNotNone(context)
61
62        # Ensure we end up with all auxv data in one packet.
63        # FIXME don't assume it all comes back in one packet.
64        self.assertEqual(context.get("response_type"), "l")
65
66        # Decode binary data.
67        content_raw = context.get("content_raw")
68        self.assertIsNotNone(content_raw)
69        return (word_size, self.decode_gdbremote_binary(content_raw))
70
71    @skipIfWindows # no auxv support.
72    @skipIfDarwin
73    def test_supports_auxv(self):
74        self.build()
75        self.set_inferior_startup_launch()
76        self.assertTrue(self.has_auxv_support())
77
78    @skipIfWindows
79    @expectedFailureNetBSD
80    def test_auxv_data_is_correct_size(self):
81        self.build()
82        self.set_inferior_startup_launch()
83
84        (word_size, auxv_data) = self.get_raw_auxv_data()
85        self.assertIsNotNone(auxv_data)
86
87        # Ensure auxv data is a multiple of 2*word_size (there should be two
88        # unsigned long fields per auxv entry).
89        self.assertEqual(len(auxv_data) % (2 * word_size), 0)
90        self.trace("auxv contains {} entries".format(len(auxv_data) / (2*word_size)))
91
92    @skipIfWindows
93    @expectedFailureNetBSD
94    def test_auxv_keys_look_valid(self):
95        self.build()
96        self.set_inferior_startup_launch()
97
98        (word_size, auxv_data) = self.get_raw_auxv_data()
99        self.assertIsNotNone(auxv_data)
100
101        # Grab endian.
102        self.reset_test_sequence()
103        self.add_process_info_collection_packets()
104        context = self.expect_gdbremote_sequence()
105        self.assertIsNotNone(context)
106
107        process_info = self.parse_process_info_response(context)
108        self.assertIsNotNone(process_info)
109        endian = process_info.get("endian")
110        self.assertIsNotNone(endian)
111
112        auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data)
113        self.assertIsNotNone(auxv_dict)
114
115        # Verify keys look reasonable.
116        for auxv_key in auxv_dict:
117            self.assertTrue(auxv_key >= 1)
118            self.assertTrue(auxv_key <= 1000)
119        self.trace("auxv dict: {}".format(auxv_dict))
120
121    @skipIfWindows
122    @expectedFailureNetBSD
123    def test_auxv_chunked_reads_work(self):
124        self.build()
125        self.set_inferior_startup_launch()
126
127        # Verify that multiple smaller offset,length reads of auxv data
128        # return the same data as a single larger read.
129
130        # Grab the auxv data with a single large read here.
131        (word_size, auxv_data) = self.get_raw_auxv_data()
132        self.assertIsNotNone(auxv_data)
133
134        # Grab endian.
135        self.reset_test_sequence()
136        self.add_process_info_collection_packets()
137        context = self.expect_gdbremote_sequence()
138        self.assertIsNotNone(context)
139
140        process_info = self.parse_process_info_response(context)
141        self.assertIsNotNone(process_info)
142        endian = process_info.get("endian")
143        self.assertIsNotNone(endian)
144
145        auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data)
146        self.assertIsNotNone(auxv_dict)
147
148        iterated_auxv_data = self.read_binary_data_in_chunks(
149            "qXfer:auxv:read::", 2 * word_size)
150        self.assertIsNotNone(iterated_auxv_data)
151
152        auxv_dict_iterated = self.build_auxv_dict(
153            endian, word_size, iterated_auxv_data)
154        self.assertIsNotNone(auxv_dict_iterated)
155
156        # Verify both types of data collection returned same content.
157        self.assertEqual(auxv_dict_iterated, auxv_dict)
158