| """Test that lldb will read additional registers from Mach-O LC_NOTE metadata.""" |
| |
| import os |
| import re |
| import subprocess |
| |
| import lldb |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test import lldbutil |
| |
| |
| class TestMetadataRegisters(TestBase): |
| NO_DEBUG_INFO_TESTCASE = True |
| |
| @requireDarwin |
| @skipIfRemote |
| def test_add_registers_via_metadata(self): |
| self.build() |
| self.aout_exe = self.getBuildArtifact("a.out") |
| lldb_corefile = self.getBuildArtifact("lldb.core") |
| metadata_corefile = self.getBuildArtifact("metadata.core") |
| bad_metadata1_corefile = self.getBuildArtifact("bad-metadata1.core") |
| bad_metadata2_corefile = self.getBuildArtifact("bad-metadata2.core") |
| add_lcnote = self.getBuildArtifact("add-lcnote") |
| |
| (target, process, t, bp) = lldbutil.run_to_source_breakpoint( |
| self, "break here", lldb.SBFileSpec("main.c") |
| ) |
| |
| self.assertTrue(process.IsValid()) |
| |
| if self.TraceOn(): |
| self.runCmd("bt") |
| self.runCmd("reg read -a") |
| |
| self.runCmd("process save-core " + lldb_corefile) |
| process.Kill() |
| target.Clear() |
| |
| cmd = ( |
| add_lcnote |
| + " -r" |
| + " -i '%s'" % lldb_corefile |
| + " -o '%s'" % metadata_corefile |
| + " -n 'process metadata' " |
| + " -s '" |
| + """{"threads":[{"register_info": |
| {"sets":["Special Registers", "General Purpose Registers"], |
| "registers":[ |
| {"name":"jar", "value":10, "bitsize": 32, "set": 0}, |
| {"name":"bar", "value":65537, "bitsize":16, "set":0}, |
| {"name":"mar", "value":65537, "bitsize":32, "set":0}, |
| {"name":"anotherpc", "value":55, "bitsize":64, "set": 1}]}}]}""" |
| + "'" |
| ) |
| call(cmd, shell=True) |
| |
| cmd = ( |
| add_lcnote |
| + " -r" |
| + " -i '%s'" % lldb_corefile |
| + " -o '%s'" % bad_metadata1_corefile |
| + " -n 'process metadata' " |
| + " -s '" |
| + """{lol im bad json}""" |
| + "'" |
| ) |
| call(cmd, shell=True) |
| |
| cmd = ( |
| add_lcnote |
| + " -r" |
| + " -i '%s'" % lldb_corefile |
| + " -o '%s'" % bad_metadata2_corefile |
| + " -n 'process metadata' " |
| + " -s '" |
| + """{"threads":[ |
| {"register_info": |
| {"sets":["a"],"registers":[{"name":"a", "value":1, "bitsize": 32, "set": 0}]}}, |
| {"register_info": |
| {"sets":["a"],"registers":[{"name":"a", "value":1, "bitsize": 32, "set": 0}]}} |
| ]}""" |
| + "'" |
| ) |
| call(cmd, shell=True) |
| |
| # Now load the corefile |
| target = self.dbg.CreateTarget("") |
| process = target.LoadCore(metadata_corefile) |
| self.assertTrue(process.IsValid()) |
| if self.TraceOn(): |
| self.runCmd("bt") |
| self.runCmd("reg read -a") |
| |
| thread = process.GetSelectedThread() |
| frame = thread.GetFrameAtIndex(0) |
| |
| # Register sets will be |
| # from LC_THREAD: |
| # General Purpose Registers |
| # Floating Point Registers |
| # Exception State Registers |
| # from LC_NOTE metadata: |
| # Special Registers |
| self.assertEqual(frame.registers[0].GetName(), "General Purpose Registers") |
| self.assertEqual(frame.registers[3].GetName(), "Special Registers") |
| |
| anotherpc = frame.registers[0].GetChildMemberWithName("anotherpc") |
| self.assertTrue(anotherpc.IsValid()) |
| self.assertEqual(anotherpc.GetValueAsUnsigned(), 0x37) |
| |
| jar = frame.registers[3].GetChildMemberWithName("jar") |
| self.assertTrue(jar.IsValid()) |
| self.assertEqual(jar.GetValueAsUnsigned(), 10) |
| self.assertEqual(jar.GetByteSize(), 4) |
| |
| bar = frame.registers[3].GetChildMemberWithName("bar") |
| self.assertTrue(bar.IsValid()) |
| self.assertEqual(bar.GetByteSize(), 2) |
| |
| mar = frame.registers[3].GetChildMemberWithName("mar") |
| self.assertTrue(mar.IsValid()) |
| self.assertEqual(mar.GetValueAsUnsigned(), 0x10001) |
| self.assertEqual(mar.GetByteSize(), 4) |
| |
| # bad1 has invalid JSON, no additional registers |
| target = self.dbg.CreateTarget("") |
| process = target.LoadCore(bad_metadata1_corefile) |
| self.assertTrue(process.IsValid()) |
| thread = process.GetSelectedThread() |
| frame = thread.GetFrameAtIndex(0) |
| gpr_found = False |
| for regset in frame.registers: |
| if regset.GetName() == "General Purpose Registers": |
| gpr_found = True |
| self.assertTrue(gpr_found) |
| |
| # bad2 has invalid JSON, more process metadata threads than |
| # LC_THREADs, and should be rejected. |
| target = self.dbg.CreateTarget("") |
| process = target.LoadCore(bad_metadata2_corefile) |
| self.assertTrue(process.IsValid()) |
| thread = process.GetSelectedThread() |
| frame = thread.GetFrameAtIndex(0) |
| metadata_regset_found = False |
| for regset in frame.registers: |
| if regset.GetName() == "a" or regset.GetName() == "b": |
| metadata_regset_found = True |
| self.assertFalse(metadata_regset_found) |