|  | import gdbremote_testcase | 
|  | from lldbsuite.test.decorators import * | 
|  | from lldbsuite.test.lldbtest import * | 
|  | from lldbsuite.test import lldbutil | 
|  |  | 
|  |  | 
|  | class TestGdbRemoteAuxvSupport(gdbremote_testcase.GdbRemoteTestCaseBase): | 
|  | AUXV_SUPPORT_FEATURE_NAME = "qXfer:auxv:read" | 
|  |  | 
|  | def has_auxv_support(self): | 
|  | procs = self.prep_debug_monitor_and_inferior() | 
|  |  | 
|  | self.add_qSupported_packets() | 
|  | context = self.expect_gdbremote_sequence() | 
|  | self.assertIsNotNone(context) | 
|  |  | 
|  | features = self.parse_qSupported_response(context) | 
|  | return ( | 
|  | self.AUXV_SUPPORT_FEATURE_NAME in features | 
|  | and features[self.AUXV_SUPPORT_FEATURE_NAME] == "+" | 
|  | ) | 
|  |  | 
|  | def get_raw_auxv_data(self): | 
|  | # Start up llgs and inferior, and check for auxv support. | 
|  | if not self.has_auxv_support(): | 
|  | self.skipTest("auxv data not supported") | 
|  |  | 
|  | # Grab pointer size for target.  We'll assume that is equivalent to an unsigned long on the target. | 
|  | # Auxv is specified in terms of pairs of unsigned longs. | 
|  | self.reset_test_sequence() | 
|  | self.add_process_info_collection_packets() | 
|  |  | 
|  | context = self.expect_gdbremote_sequence() | 
|  | self.assertIsNotNone(context) | 
|  |  | 
|  | proc_info = self.parse_process_info_response(context) | 
|  | self.assertIsNotNone(proc_info) | 
|  | self.assertIn("ptrsize", proc_info) | 
|  | word_size = int(proc_info["ptrsize"]) | 
|  |  | 
|  | OFFSET = 0 | 
|  | LENGTH = 0x400 | 
|  |  | 
|  | # Grab the auxv data. | 
|  | self.reset_test_sequence() | 
|  | self.test_sequence.add_log_lines( | 
|  | [ | 
|  | "read packet: $qXfer:auxv:read::{:x},{:x}:#00".format(OFFSET, LENGTH), | 
|  | { | 
|  | "direction": "send", | 
|  | "regex": re.compile( | 
|  | r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL | 
|  | ), | 
|  | "capture": {1: "response_type", 2: "content_raw"}, | 
|  | }, | 
|  | ], | 
|  | True, | 
|  | ) | 
|  |  | 
|  | context = self.expect_gdbremote_sequence() | 
|  | self.assertIsNotNone(context) | 
|  |  | 
|  | # Ensure we end up with all auxv data in one packet. | 
|  | # FIXME don't assume it all comes back in one packet. | 
|  | self.assertEqual(context.get("response_type"), "l") | 
|  |  | 
|  | # Decode binary data. | 
|  | content_raw = context.get("content_raw") | 
|  | self.assertIsNotNone(content_raw) | 
|  | return (word_size, self.decode_gdbremote_binary(content_raw)) | 
|  |  | 
|  | @skipIfWindows  # no auxv support. | 
|  | @skipIfDarwin | 
|  | def test_supports_auxv(self): | 
|  | self.build() | 
|  | self.set_inferior_startup_launch() | 
|  | self.assertTrue(self.has_auxv_support()) | 
|  |  | 
|  | @skipIfWindows | 
|  | @expectedFailureNetBSD | 
|  | def test_auxv_data_is_correct_size(self): | 
|  | self.build() | 
|  | self.set_inferior_startup_launch() | 
|  |  | 
|  | (word_size, auxv_data) = self.get_raw_auxv_data() | 
|  | self.assertIsNotNone(auxv_data) | 
|  |  | 
|  | # Ensure auxv data is a multiple of 2*word_size (there should be two | 
|  | # unsigned long fields per auxv entry). | 
|  | self.assertEqual(len(auxv_data) % (2 * word_size), 0) | 
|  | self.trace("auxv contains {} entries".format(len(auxv_data) / (2 * word_size))) | 
|  |  | 
|  | @skipIfWindows | 
|  | @expectedFailureNetBSD | 
|  | def test_auxv_keys_look_valid(self): | 
|  | self.build() | 
|  | self.set_inferior_startup_launch() | 
|  |  | 
|  | (word_size, auxv_data) = self.get_raw_auxv_data() | 
|  | self.assertIsNotNone(auxv_data) | 
|  |  | 
|  | # Grab endian. | 
|  | self.reset_test_sequence() | 
|  | self.add_process_info_collection_packets() | 
|  | context = self.expect_gdbremote_sequence() | 
|  | self.assertIsNotNone(context) | 
|  |  | 
|  | process_info = self.parse_process_info_response(context) | 
|  | self.assertIsNotNone(process_info) | 
|  | endian = process_info.get("endian") | 
|  | self.assertIsNotNone(endian) | 
|  |  | 
|  | auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data) | 
|  | self.assertIsNotNone(auxv_dict) | 
|  |  | 
|  | # Verify keys look reasonable. While AUX values are most commonly | 
|  | # small (usually smaller than 50), they can sometimes be larger. | 
|  | self.trace("auxv dict: {}".format(auxv_dict)) | 
|  | for auxv_key in auxv_dict: | 
|  | self.assertGreaterEqual(auxv_key, 1) | 
|  | self.assertLessEqual(auxv_key, 2500) | 
|  |  | 
|  | @skipIfWindows | 
|  | @expectedFailureNetBSD | 
|  | def test_auxv_chunked_reads_work(self): | 
|  | self.build() | 
|  | self.set_inferior_startup_launch() | 
|  |  | 
|  | # Verify that multiple smaller offset,length reads of auxv data | 
|  | # return the same data as a single larger read. | 
|  |  | 
|  | # Grab the auxv data with a single large read here. | 
|  | (word_size, auxv_data) = self.get_raw_auxv_data() | 
|  | self.assertIsNotNone(auxv_data) | 
|  |  | 
|  | # Grab endian. | 
|  | self.reset_test_sequence() | 
|  | self.add_process_info_collection_packets() | 
|  | context = self.expect_gdbremote_sequence() | 
|  | self.assertIsNotNone(context) | 
|  |  | 
|  | process_info = self.parse_process_info_response(context) | 
|  | self.assertIsNotNone(process_info) | 
|  | endian = process_info.get("endian") | 
|  | self.assertIsNotNone(endian) | 
|  |  | 
|  | auxv_dict = self.build_auxv_dict(endian, word_size, auxv_data) | 
|  | self.assertIsNotNone(auxv_dict) | 
|  |  | 
|  | iterated_auxv_data = self.read_binary_data_in_chunks( | 
|  | "qXfer:auxv:read::", 2 * word_size | 
|  | ) | 
|  | self.assertIsNotNone(iterated_auxv_data) | 
|  |  | 
|  | auxv_dict_iterated = self.build_auxv_dict(endian, word_size, iterated_auxv_data) | 
|  | self.assertIsNotNone(auxv_dict_iterated) | 
|  |  | 
|  | # Verify both types of data collection returned same content. | 
|  | self.assertEqual(auxv_dict_iterated, auxv_dict) |