File: TestSkinnyCorefile.py

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (163 lines) | stat: -rw-r--r-- 6,982 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""Test that lldb can create a skinny corefile, and load all available libraries correctly."""


import os
import re
import subprocess

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestSkinnyCorefile(TestBase):
    @skipIfOutOfTreeDebugserver  # newer debugserver required for these qMemoryRegionInfo types
    @skipIf(
        debug_info=no_match(["dsym"]),
        bugnumber="This test is looking explicitly for a dSYM",
    )
    @skipUnlessDarwin
    @skipIfRemote
    def test_lc_note(self):
        self.build()
        self.aout_exe = self.getBuildArtifact("a.out")
        self.aout_dsym = self.getBuildArtifact("a.out.dSYM")
        self.to_be_removed_dylib = self.getBuildArtifact("libto-be-removed.dylib")
        self.to_be_removed_dsym = self.getBuildArtifact("libto-be-removed.dylib.dSYM")
        self.corefile = self.getBuildArtifact("process.core")
        self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh")

        # After the corefile is created, we'll move a.out and a.out.dSYM
        # into hide.noindex and lldb will have to use the
        # LLDB_APPLE_DSYMFORUUID_EXECUTABLE script to find them.
        self.hide_dir = self.getBuildArtifact("hide.noindex")
        lldbutil.mkdir_p(self.hide_dir)
        self.hide_aout_exe = self.getBuildArtifact("hide.noindex/a.out")
        self.hide_aout_dsym = self.getBuildArtifact("hide.noindex/a.out.dSYM")

        # We can hook in our dsym-for-uuid shell script to lldb with
        # this env var instead of requiring a defaults write.
        os.environ["LLDB_APPLE_DSYMFORUUID_EXECUTABLE"] = self.dsym_for_uuid
        self.addTearDownHook(
            lambda: os.environ.pop("LLDB_APPLE_DSYMFORUUID_EXECUTABLE", None)
        )

        dwarfdump_uuid_regex = re.compile("UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*")
        dwarfdump_cmd_output = subprocess.check_output(
            ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True
        ).decode("utf-8")
        aout_uuid = None
        for line in dwarfdump_cmd_output.splitlines():
            match = dwarfdump_uuid_regex.search(line)
            if match:
                aout_uuid = match.group(1)
        self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out")

        ###  Create our dsym-for-uuid shell script which returns self.hide_aout_exe.
        shell_cmds = [
            "#! /bin/sh",
            "# the last argument is the uuid",
            "while [ $# -gt 1 ]",
            "do",
            "  shift",
            "done",
            "ret=0",
            'echo "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>"',
            'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"',
            'echo "<plist version=\\"1.0\\">"',
            "",
            'if [ "$1" = "%s" ]' % aout_uuid,
            "then",
            "  uuid=%s" % aout_uuid,
            "  bin=%s" % self.hide_aout_exe,
            "  dsym=%s.dSYM/Contents/Resources/DWARF/%s"
            % (self.hide_aout_exe, os.path.basename(self.hide_aout_exe)),
            "fi",
            'if [ -z "$uuid" -o -z "$bin" -o ! -f "$bin" ]',
            "then",
            '  echo "<key>DBGError</key><string>not found</string>"',
            '  echo "</plist>"',
            "  exit 1",
            "fi",
            'echo "<dict><key>$uuid</key><dict>"',
            "",
            'echo "<key>DBGArchitecture</key><string>x86_64</string>"',
            'echo "<key>DBGDSYMPath</key><string>$dsym</string>"',
            'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"',
            'echo "</dict></dict></plist>"',
            "exit $ret",
        ]

        with open(self.dsym_for_uuid, "w") as writer:
            for l in shell_cmds:
                writer.write(l + "\n")

        os.chmod(self.dsym_for_uuid, 0o755)

        # Launch a live process with a.out, libto-be-removed.dylib,
        # libpresent.dylib all in their original locations, create
        # a corefile at the breakpoint.
        (target, process, t, bp) = lldbutil.run_to_source_breakpoint(
            self, "break here", lldb.SBFileSpec("present.c")
        )

        self.assertTrue(process.IsValid())

        if self.TraceOn():
            self.runCmd("bt")
            self.runCmd("image list")

        self.runCmd("process save-core " + self.corefile)
        process.Kill()
        target.Clear()

        # Move the main binary and its dSYM into the hide.noindex
        # directory.  Now the only way lldb can find them is with
        # the LLDB_APPLE_DSYMFORUUID_EXECUTABLE shell script -
        # so we're testing that this dSYM discovery method works.
        os.rename(self.aout_exe, self.hide_aout_exe)
        os.rename(self.aout_dsym, self.hide_aout_dsym)

        # Completely remove the libto-be-removed.dylib, so we're
        # testing that lldb handles an unavailable binary correctly,
        # and non-dirty memory from this binary (e.g. the executing
        # instructions) are NOT included in the corefile.
        os.unlink(self.to_be_removed_dylib)
        shutil.rmtree(self.to_be_removed_dsym)

        # Now load the corefile
        self.target = self.dbg.CreateTarget("")
        self.process = self.target.LoadCore(self.corefile)
        self.assertTrue(self.process.IsValid())
        if self.TraceOn():
            self.runCmd("image list")
            self.runCmd("bt")

        self.assertTrue(self.process.IsValid())
        self.assertTrue(self.process.GetSelectedThread().IsValid())

        # f0 is present() in libpresent.dylib
        f0 = self.process.GetSelectedThread().GetFrameAtIndex(0)
        to_be_removed_dirty_data = f0.FindVariable("to_be_removed_dirty_data")
        self.assertEqual(to_be_removed_dirty_data.GetValueAsUnsigned(), 20)

        present_heap_buf = f0.FindVariable("present_heap_buf")
        self.assertIn("have ints 5 20 20 5", present_heap_buf.GetSummary())

        # f1 is to_be_removed() in libto-be-removed.dylib
        # it has been removed since the corefile was created,
        # and the instructions for this frame should NOT be included
        # in the corefile.  They were not dirty pages.
        f1 = self.process.GetSelectedThread().GetFrameAtIndex(1)
        err = lldb.SBError()
        uint = self.process.ReadUnsignedFromMemory(f1.GetPC(), 4, err)
        self.assertTrue(err.Fail())

        # TODO Future testing could check that read-only constant data
        # (main_const_data, present_const_data) can be read both as an
        # SBValue and in an expression -- which means lldb needs to read
        # them out of the binaries, they are not present in the corefile.
        # And checking file-scope dirty data (main_dirty_data,
        # present_dirty_data) the same way would be good, instead of just
        # checking the heap and stack like are being done right now.