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