| import lldb | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test import lldbutil | |
| @requireDarwin | |
| @skipIf(archs=no_match(["arm64"])) | |
| class TestArmPointerMetadataStripping(TestBase): | |
| def test(self): | |
| self.build() | |
| target, process, thread, bkpt = lldbutil.run_to_name_breakpoint(self, "foo") | |
| # Step over the first two instructions of foo in order to | |
| # toggle the bit of fp and save it on the stack: | |
| # orr x29, x29, #0x1000000000000000 | |
| # stp x29, x30, [sp, #-16]! | |
| # This is effectively adding metadata to the CFA of the caller frame (main). | |
| thread.StepInstruction(False) | |
| thread.StepInstruction(False) | |
| # The location of `argv` has been artificially made equal to the CFA of the frame. | |
| # As such, it should have the metadata artificially set previously. | |
| argv_addr = thread.frames[1].GetValueForVariablePath("&argv") | |
| self.assertTrue(argv_addr.IsValid()) | |
| argv_addr_uint = argv_addr.GetValueAsUnsigned() | |
| self.assertNotEqual((argv_addr_uint & (1 << 60)), 0) | |
| # GetCFA strips metadata. | |
| cfa = thread.frames[1].GetCFA() | |
| self.assertEqual((cfa & (1 << 60)), 0) | |
| # If the test worked correctly, the cfa and the location should be identical, | |
| # modulo the metadata. | |
| self.assertEqual(cfa | (1 << 60), argv_addr_uint) |