163 lines · python
1"""Test that lldb can create a skinny corefile, and load all available libraries correctly."""2 3 4import os5import re6import subprocess7 8import lldb9from lldbsuite.test.decorators import *10from lldbsuite.test.lldbtest import *11from lldbsuite.test import lldbutil12 13 14class TestSkinnyCorefile(TestBase):15 @skipIf(16 debug_info=no_match(["dsym"]),17 bugnumber="This test is looking explicitly for a dSYM",18 )19 @skipUnlessDarwin20 @skipIfRemote21 def test_lc_note(self):22 self.build()23 self.aout_exe = self.getBuildArtifact("a.out")24 self.aout_dsym = self.getBuildArtifact("a.out.dSYM")25 self.to_be_removed_dylib = self.getBuildArtifact("libto-be-removed.dylib")26 self.to_be_removed_dsym = self.getBuildArtifact("libto-be-removed.dylib.dSYM")27 self.corefile = self.getBuildArtifact("process.core")28 self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh")29 30 # After the corefile is created, we'll move a.out and a.out.dSYM31 # into hide.noindex and lldb will have to use the32 # LLDB_APPLE_DSYMFORUUID_EXECUTABLE script to find them.33 self.hide_dir = self.getBuildArtifact("hide.noindex")34 lldbutil.mkdir_p(self.hide_dir)35 self.hide_aout_exe = self.getBuildArtifact("hide.noindex/a.out")36 self.hide_aout_dsym = self.getBuildArtifact("hide.noindex/a.out.dSYM")37 38 # We can hook in our dsym-for-uuid shell script to lldb with39 # this env var instead of requiring a defaults write.40 os.environ["LLDB_APPLE_DSYMFORUUID_EXECUTABLE"] = self.dsym_for_uuid41 self.addTearDownHook(42 lambda: os.environ.pop("LLDB_APPLE_DSYMFORUUID_EXECUTABLE", None)43 )44 45 dwarfdump_uuid_regex = re.compile(r"UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*")46 dwarfdump_cmd_output = subprocess.check_output(47 ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True48 ).decode("utf-8")49 aout_uuid = None50 for line in dwarfdump_cmd_output.splitlines():51 match = dwarfdump_uuid_regex.search(line)52 if match:53 aout_uuid = match.group(1)54 self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out")55 56 ### Create our dsym-for-uuid shell script which returns self.hide_aout_exe.57 shell_cmds = [58 "#! /bin/sh",59 "# the last argument is the uuid",60 "while [ $# -gt 1 ]",61 "do",62 " shift",63 "done",64 "ret=0",65 'echo "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>"',66 'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"',67 'echo "<plist version=\\"1.0\\">"',68 "",69 'if [ "$1" = "%s" ]' % aout_uuid,70 "then",71 " uuid=%s" % aout_uuid,72 " bin=%s" % self.hide_aout_exe,73 " dsym=%s.dSYM/Contents/Resources/DWARF/%s"74 % (self.hide_aout_exe, os.path.basename(self.hide_aout_exe)),75 "fi",76 'if [ -z "$uuid" -o -z "$bin" -o ! -f "$bin" ]',77 "then",78 ' echo "<key>DBGError</key><string>not found</string>"',79 ' echo "</plist>"',80 " exit 1",81 "fi",82 'echo "<dict><key>$uuid</key><dict>"',83 "",84 'echo "<key>DBGArchitecture</key><string>x86_64</string>"',85 'echo "<key>DBGDSYMPath</key><string>$dsym</string>"',86 'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"',87 'echo "</dict></dict></plist>"',88 "exit $ret",89 ]90 91 with open(self.dsym_for_uuid, "w") as writer:92 for l in shell_cmds:93 writer.write(l + "\n")94 95 os.chmod(self.dsym_for_uuid, 0o755)96 97 # Launch a live process with a.out, libto-be-removed.dylib,98 # libpresent.dylib all in their original locations, create99 # a corefile at the breakpoint.100 (target, process, t, bp) = lldbutil.run_to_source_breakpoint(101 self, "break here", lldb.SBFileSpec("present.c")102 )103 104 self.assertTrue(process.IsValid())105 106 if self.TraceOn():107 self.runCmd("bt")108 self.runCmd("image list")109 110 self.runCmd("process save-core " + self.corefile)111 process.Kill()112 target.Clear()113 114 # Move the main binary and its dSYM into the hide.noindex115 # directory. Now the only way lldb can find them is with116 # the LLDB_APPLE_DSYMFORUUID_EXECUTABLE shell script -117 # so we're testing that this dSYM discovery method works.118 os.rename(self.aout_exe, self.hide_aout_exe)119 os.rename(self.aout_dsym, self.hide_aout_dsym)120 121 # Completely remove the libto-be-removed.dylib, so we're122 # testing that lldb handles an unavailable binary correctly,123 # and non-dirty memory from this binary (e.g. the executing124 # instructions) are NOT included in the corefile.125 os.unlink(self.to_be_removed_dylib)126 shutil.rmtree(self.to_be_removed_dsym)127 128 # Now load the corefile129 self.target = self.dbg.CreateTarget("")130 self.process = self.target.LoadCore(self.corefile)131 self.assertTrue(self.process.IsValid())132 if self.TraceOn():133 self.runCmd("image list")134 self.runCmd("bt")135 136 self.assertTrue(self.process.IsValid())137 self.assertTrue(self.process.GetSelectedThread().IsValid())138 139 # f0 is present() in libpresent.dylib140 f0 = self.process.GetSelectedThread().GetFrameAtIndex(0)141 to_be_removed_dirty_data = f0.FindVariable("to_be_removed_dirty_data")142 self.assertEqual(to_be_removed_dirty_data.GetValueAsUnsigned(), 20)143 144 present_heap_buf = f0.FindVariable("present_heap_buf")145 self.assertIn("have ints 5 20 20 5", present_heap_buf.GetSummary())146 147 # f1 is to_be_removed() in libto-be-removed.dylib148 # it has been removed since the corefile was created,149 # and the instructions for this frame should NOT be included150 # in the corefile. They were not dirty pages.151 f1 = self.process.GetSelectedThread().GetFrameAtIndex(1)152 err = lldb.SBError()153 uint = self.process.ReadUnsignedFromMemory(f1.GetPC(), 4, err)154 self.assertTrue(err.Fail())155 156 # TODO Future testing could check that read-only constant data157 # (main_const_data, present_const_data) can be read both as an158 # SBValue and in an expression -- which means lldb needs to read159 # them out of the binaries, they are not present in the corefile.160 # And checking file-scope dirty data (main_dirty_data,161 # present_dirty_data) the same way would be good, instead of just162 # checking the heap and stack like are being done right now.163